Merge branch 'stable-6.0' into stable-6.1
* stable-6.0:
Shortcut during git fetch for avoiding looping through all local refs
FetchCommand: fix fetchSubmodules to work on a Ref to a blob
Silence API warnings introduced by I466dcde6
Allow the exclusions of refs prefixes from bitmap
PackWriterBitmapPreparer: do not include annotated tags in bitmap
BatchingProgressMonitor: avoid int overflow when computing percentage
Speedup GC listing objects referenced from reflogs
FileSnapshotTest: Add more MISSING_FILE coverage
Change-Id: Ib5055f2f3b8a313c178d6f6c7c5630285ad5a726
diff --git a/.bazelrc b/.bazelrc
index e24be88..8c32661 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -3,8 +3,33 @@
build --experimental_strict_action_env
build --action_env=PATH
build --disk_cache=~/.gerritcodereview/bazel-cache/cas
-build --java_toolchain //tools:error_prone_warnings_toolchain
+
+# Builds using remote_jdk11, executes using remote_jdk11 or local_jdk
+build --java_language_version=11
+build --java_runtime_version=remotejdk_11
+build --tool_java_language_version=11
+build --tool_java_runtime_version=remotejdk_11
+
+# Builds and executes on RBE using remotejdk_11
+build:remote --java_language_version=11
+build:remote --java_runtime_version=remotejdk_11
+build:remote --tool_java_language_version=11
+build:remote --tool_java_runtime_version=remotejdk_11
+
+# Builds using remote_jdk17, executes using remote_jdk11 or local_jdk
+build:java17 --java_language_version=17
+build:java17 --java_runtime_version=remotejdk_17
+build:java17 --tool_java_language_version=17
+build:java17 --tool_java_runtime_version=remotejdk_17
+
+# Builds and executes on RBE using remotejdk_17
+build:remote17 --java_language_version=17
+build:remote17 --java_runtime_version=remotejdk_17
+build:remote17 --tool_java_language_version=17
+build:remote17 --tool_java_runtime_version=remotejdk_17
test --build_tests_only
test --test_output=errors
+import %workspace%/tools/remote-bazelrc
+
diff --git a/.bazelversion b/.bazelversion
index fcdb2e1..0062ac9 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-4.0.0
+5.0.0
diff --git a/.mailmap b/.mailmap
index f0bc990..f0af49b 100644
--- a/.mailmap
+++ b/.mailmap
@@ -12,6 +12,7 @@
Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com>
Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com>
Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <zivkov@gmail.com>
+Sebastian Schuberth <sschuberth@gmail.com> Sebastian Schuberth <sebastian.schuberth@bosch.io>
Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <sop@google.com>
Shawn Pearce <spearce@spearce.org> Shawn Pearce <sop@google.com>
Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <spearce@spearce.org>
diff --git a/DEPENDENCIES b/DEPENDENCIES
index ebbe480..93fa850 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -1,69 +1,68 @@
maven/mavencentral/args4j/args4j/2.33, MIT, approved, CQ11068
-maven/mavencentral/com.google.code.gson/gson/2.8.7, Apache-2.0, approved, CQ23496
-maven/mavencentral/com.googlecode.javaewah/JavaEWAH/1.1.12, Apache-2.0, approved, CQ11658
+maven/mavencentral/com.google.code.gson/gson/2.8.9, Apache-2.0, approved, CQ23496
+maven/mavencentral/com.googlecode.javaewah/JavaEWAH/1.1.13, Apache-2.0, approved, CQ11658
maven/mavencentral/com.jcraft/jsch/0.1.55, BSD-3-Clause, approved, CQ19435
maven/mavencentral/com.jcraft/jzlib/1.1.1, BSD-2-Clause, approved, CQ6218
maven/mavencentral/commons-codec/commons-codec/1.11, Apache-2.0 AND BSD-3-Clause, approved, CQ15971
maven/mavencentral/commons-logging/commons-logging/1.2, Apache-2.0, approved, CQ10162
-maven/mavencentral/javax.servlet/javax.servlet-api/3.1.0, Apache-2.0 AND (CDDL-1.1 OR GPL-2.0 WITH Classpath-exception-2.0), approved, CQ7248
-maven/mavencentral/junit/junit/4.13, , approved, CQ22796
-maven/mavencentral/log4j/log4j/1.2.15, Apache-2.0, approved, CQ7837
+maven/mavencentral/javax.servlet/javax.servlet-api/4.0.0, , approved, CQ16125
+maven/mavencentral/junit/junit/4.13.2, EPL-2.0, approved, CQ23636
maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.9.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/net.bytebuddy/byte-buddy/1.9.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/net.i2p.crypto/eddsa/0.3.0, CC0-1.0, approved, CQ22537
+maven/mavencentral/net.java.dev.jna/jna-platform/5.8.0, Apache-2.0 OR LGPL-2.1-or-later, approved, CQ23218
+maven/mavencentral/net.java.dev.jna/jna/5.8.0, Apache-2.0 OR LGPL-2.1-or-later, approved, CQ23217
maven/mavencentral/net.sf.jopt-simple/jopt-simple/4.6, MIT, approved, clearlydefined
-maven/mavencentral/org.apache.ant/ant-launcher/1.10.10, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560
-maven/mavencentral/org.apache.ant/ant/1.10.10, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560
-maven/mavencentral/org.apache.commons/commons-compress/1.20, Apache-2.0 AND BSD-3-Clause AND LicenseRef-Public-Domain, approved, CQ21771
+maven/mavencentral/org.apache.ant/ant-launcher/1.10.12, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560
+maven/mavencentral/org.apache.ant/ant/1.10.12, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560
+maven/mavencentral/org.apache.commons/commons-compress/1.21, Apache-2.0 AND BSD-3-Clause AND bzip2-1.0.6 AND LicenseRef-Public-Domain, approved, CQ23710
maven/mavencentral/org.apache.commons/commons-math3/3.2, Apache-2.0, approved, clearlydefined
maven/mavencentral/org.apache.httpcomponents/httpclient/4.5.13, Apache-2.0 AND LicenseRef-Public-Domain, approved, CQ23527
maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.14, Apache-2.0, approved, CQ23528
-maven/mavencentral/org.apache.sshd/sshd-common/2.7.0, Apache-2.0 and ISC, approved, CQ23469
-maven/mavencentral/org.apache.sshd/sshd-core/2.7.0, Apache-2.0, approved, CQ23469
-maven/mavencentral/org.apache.sshd/sshd-osgi/2.7.0, Apache-2.0 and ISC, approved, CQ23469
-maven/mavencentral/org.apache.sshd/sshd-sftp/2.7.0, Apache-2.0, approved, CQ23470
+maven/mavencentral/org.apache.sshd/sshd-osgi/2.8.0, Apache-2.0, approved, CQ23892
+maven/mavencentral/org.apache.sshd/sshd-sftp/2.8.0, Apache-2.0, approved, CQ23893
maven/mavencentral/org.assertj/assertj-core/3.20.2, Apache-2.0, approved, clearlydefined
-maven/mavencentral/org.bouncycastle/bcpg-jdk15on/1.69, MIT and Apache-2.0, approved, CQ23472
-maven/mavencentral/org.bouncycastle/bcpkix-jdk15on/1.69, MIT, approved, CQ23473
-maven/mavencentral/org.bouncycastle/bcprov-jdk15on/1.69, MIT, approved, CQ23471
-maven/mavencentral/org.bouncycastle/bcutil-jdk15on/1.69, MIT, approved, CQ23474
-maven/mavencentral/org.eclipse.jetty/jetty-http/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jetty/jetty-io/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jetty/jetty-security/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jetty/jetty-server/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jetty/jetty-servlet/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jetty/jetty-util-ajax/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jetty/jetty-util/9.4.43.v20210629, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.archive/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.gpg.bc/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.apache/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.server/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.http/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.ssh/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.jsch/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.test/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ui/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit/5.13.0-SNAPSHOT, , approved, eclipse
-maven/mavencentral/org.hamcrest/hamcrest-core/1.3, BSD-2-Clause, approved, CQ7063
-maven/mavencentral/org.hamcrest/hamcrest/2.2, BSD-2-Clause, approved, clearlydefined
-maven/mavencentral/org.mockito/mockito-core/2.23.0, MIT, approved, CQ17976
+maven/mavencentral/org.bouncycastle/bcpg-jdk15on/1.70, Apache-2.0, approved, #1713
+maven/mavencentral/org.bouncycastle/bcpkix-jdk15on/1.70, MIT, approved, clearlydefined
+maven/mavencentral/org.bouncycastle/bcprov-jdk15on/1.70, MIT, approved, #1712
+maven/mavencentral/org.bouncycastle/bcutil-jdk15on/1.70, MIT, approved, clearlydefined
+maven/mavencentral/org.eclipse.jetty.toolchain/jetty-servlet-api/4.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jetty/jetty-http/10.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jetty/jetty-io/10.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jetty/jetty-security/10.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jetty/jetty-server/10.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jetty/jetty-servlet/10.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jetty/jetty-util/10.0.6, EPL-2.0 OR Apache-2.0, approved, rt.jetty
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.archive/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.gpg.bc/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.apache/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.server/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.http/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.ssh/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.agent/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.jsch/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.test/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ui/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit/6.1.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.hamcrest/hamcrest-core/1.3, BSD-2-Clause, approved, CQ11429
+maven/mavencentral/org.mockito/mockito-core/2.23.0, Apache-2.0 AND MIT, approved, #958
maven/mavencentral/org.objenesis/objenesis/2.6, Apache-2.0, approved, CQ15478
-maven/mavencentral/org.openjdk.jmh/jmh-core/1.32, GPL-2.0, approved, CQ23499
-maven/mavencentral/org.openjdk.jmh/jmh-generator-annprocess/1.32, GPL-2.0, approved, CQ23500
-maven/mavencentral/org.osgi/org.osgi.core/4.3.1, Apache-2.0, approved, CQ10111
-maven/mavencentral/org.slf4j/jcl-over-slf4j/1.7.30, Apache-2.0, approved, CQ12843
+maven/mavencentral/org.openjdk.jmh/jmh-core/1.32, GPL-2.0-only with Classpath-exception-2.0, approved, #959
+maven/mavencentral/org.openjdk.jmh/jmh-generator-annprocess/1.32, GPL-2.0-only with Classpath-exception-2.0, approved, #962
+maven/mavencentral/org.osgi/org.osgi.core/6.0.0, Apache-2.0, approved, #1794
+maven/mavencentral/org.slf4j/jcl-over-slf4j/1.7.32, Apache-2.0, approved, CQ12843
maven/mavencentral/org.slf4j/slf4j-api/1.7.30, MIT, approved, CQ13368
-maven/mavencentral/org.slf4j/slf4j-log4j12/1.7.30, MIT, approved, CQ7665
+maven/mavencentral/org.slf4j/slf4j-simple/1.7.30, MIT, approved, CQ7952
maven/mavencentral/org.tukaani/xz/1.9, LicenseRef-Public-Domain, approved, CQ23498
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index b4a0c1d..612b845 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -45,7 +45,8 @@
| `core.streamFileThreshold` | `50 MiB` | ⃞ | The size threshold beyond which objects must be streamed. |
| `core.supportsAtomicFileCreation` | `true` | ⃞ | Whether the filesystem supports atomic file creation. |
| `core.symlinks` | Auto detect if filesystem supports symlinks| ✅ | If false, symbolic links are checked out as small plain files that contain the link text. |
-| `core.trustFolderStat` | `true` | ⃞ | Whether to trust the pack folder's modification time. If `false` JGit will always scan the `.git/objects/pack` folder to check for new pack files. This can help to workaround caching issues on NFS, but reduces performance. If set to `true` it uses the `lastmodified` attribute of the folder and assumes that no new pack files can be in this folder if its modification time has not changed. |
+| `core.trustFolderStat` | `true` | ⃞ | Whether to trust the pack folder's, packed-refs file's and loose-objects folder's file attributes (Java equivalent of stat command on *nix). When looking for pack files, if `false` JGit will always scan the `.git/objects/pack` folder and if set to `true` it assumes that pack files are unchanged if the file attributes of the pack folder are unchanged. When getting the list of packed refs, if `false` JGit will always read the packed-refs file and if set to `true` it uses the file attributes of the packed-refs file and will only read it if a file attribute has changed. When looking for loose objects, if `false` and if a loose object is not found, JGit will open and close a stream to `.git/objects` folder (which can refresh its directory listing, at least on some NFS clients) and retry looking for that loose object. Setting this option to `false` can help to workaround caching issues on NFS, but reduces performance. |
+| `core.trustPackedRefsStat` | `unset` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the packed-refs file. If `never` JGit will ignore the file attributes of the packed-refs file and always read it. If `always` JGit will trust the file attributes of the packed-refs file and will only read it if a file attribute has changed. `after_open` behaves the same as `always`, except that the packed-refs file is opened and closed before its file attributes are considered. An open/close of the packed-refs file is known to refresh its file attributes, at least on some NFS clients. If `unset`, JGit will use the behavior described in `trustFolderStat`. |
| `core.worktree` | Root directory of the working tree if it is not the parent directory of the `.git` directory | ✅ | The path to the root of the working tree. |
## __gc__ options
diff --git a/WORKSPACE b/WORKSPACE
index 51a815e..040617e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,23 +1,6 @@
workspace(name = "jgit")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-http_archive(
- name = "bazel_skylib",
- sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a",
- strip_prefix = "bazel-skylib-0.8.0",
- urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz"],
-)
-
-# Check Bazel version when invoked by Bazel directly
-load("//tools:bazelisk_version.bzl", "bazelisk_version")
-
-bazelisk_version(name = "bazelisk_version")
-
-load("@bazelisk_version//:check.bzl", "check_bazel_version")
-
-check_bazel_version()
-
load("//tools:bazlets.bzl", "load_bazlets")
load_bazlets(commit = "f30a992da9fc855dce819875afb59f9dd6f860cd")
@@ -28,32 +11,18 @@
)
http_archive(
- name = "openjdk15_linux_archive",
- build_file_content = """
-java_runtime(name = 'runtime', srcs = glob(['**']), visibility = ['//visibility:public'])
-exports_files(["WORKSPACE"], visibility = ["//visibility:public"])
-""",
- sha256 = "0a38f1138c15a4f243b75eb82f8ef40855afcc402e3c2a6de97ce8235011b1ad",
- strip_prefix = "zulu15.27.17-ca-jdk15.0.0-linux_x64",
+ name = "rbe_jdk11",
+ sha256 = "766796de71916118e528b9f4334c29c9c9b4e926227bf3264dee555e6a4306c8",
+ strip_prefix = "rbe_autoconfig-2.0.0",
urls = [
- "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz",
- "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz",
+ "https://gerrit-bazel.storage.googleapis.com/rbe_autoconfig/v2.0.0.tar.gz",
+ "https://github.com/davido/rbe_autoconfig/archive/v2.0.0.tar.gz",
],
)
-http_archive(
- name = "openjdk15_darwin_archive",
- build_file_content = """
-java_runtime(name = 'runtime', srcs = glob(['**']), visibility = ['//visibility:public'])
-exports_files(["WORKSPACE"], visibility = ["//visibility:public"])
-""",
- sha256 = "f80b2e0512d9d8a92be24497334c974bfecc8c898fc215ce0e76594f00437482",
- strip_prefix = "zulu15.27.17-ca-jdk15.0.0-macosx_x64",
- urls = [
- "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz",
- "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz",
- ],
-)
+register_toolchains("//tools:error_prone_warnings_toolchain_java11_definition")
+
+register_toolchains("//tools:error_prone_warnings_toolchain_java17_definition")
JMH_VERS = "1.32"
@@ -123,14 +92,14 @@
maven_jar(
name = "sshd-osgi",
- artifact = "org.apache.sshd:sshd-osgi:2.7.0",
- sha1 = "a101aad0f79ad424498098f7e91c39d3d92177c1",
+ artifact = "org.apache.sshd:sshd-osgi:2.8.0",
+ sha1 = "b2a59b73c045f40d5722b9160d4f909a646d86c9",
)
maven_jar(
name = "sshd-sftp",
- artifact = "org.apache.sshd:sshd-sftp:2.7.0",
- sha1 = "0c9eff7145e20b338c1dd6aca36ba93ed7c0147c",
+ artifact = "org.apache.sshd:sshd-sftp:2.8.0",
+ sha1 = "d3cd9bc8d335b3ed1a86d2965deb4d202de27442",
)
maven_jar(
@@ -239,8 +208,8 @@
maven_jar(
name = "gson",
- artifact = "com.google.code.gson:gson:2.8.8",
- sha1 = "431fc3cbc0ff81abdbfde070062741089c3ba874",
+ artifact = "com.google.code.gson:gson:2.8.9",
+ sha1 = "8a432c1d6825781e21a02db2e2c33c5fde2833b9",
)
JETTY_VER = "10.0.6"
@@ -294,32 +263,32 @@
src_sha1 = "f35f5525a5d30dc1237b85457d758d578e3ce8d0",
)
-BOUNCYCASTLE_VER = "1.69"
+BOUNCYCASTLE_VER = "1.70"
maven_jar(
name = "bcpg",
artifact = "org.bouncycastle:bcpg-jdk15on:" + BOUNCYCASTLE_VER,
- sha1 = "d99a08c3f651b26e8eb668e941b0bbd2c09ece08",
- src_sha1 = "de1fc261b44a8eb60583413a31ffc98ce3dce38b",
+ sha1 = "062f72ec06f31a6c31a3f3355fce0384b21126d7",
+ src_sha1 = "9dee73ad926752ee3b421a7dc4531287166ccf36",
)
maven_jar(
name = "bcprov",
artifact = "org.bouncycastle:bcprov-jdk15on:" + BOUNCYCASTLE_VER,
- sha1 = "91e1628251cf3ca90093ce9d0fe67e5b7dab3850",
- src_sha1 = "67dc6476845f6b29cb520b5df61db65ae56718e4",
+ sha1 = "4636a0d01f74acaf28082fb62b317f1080118371",
+ src_sha1 = "6245e15dd47e5fc33cff275df61662e0a8e5958f",
)
maven_jar(
name = "bcutil",
artifact = "org.bouncycastle:bcutil-jdk15on:" + BOUNCYCASTLE_VER,
- sha1 = "c3edf93d346e97f64f041e448e7455c39c7eff64",
- src_sha1 = "deeb3fbbf373e05e2a20941f9a8ce90e9aeab3d2",
+ sha1 = "54280e7195a7430d7911ded93fc01e07300b9526",
+ src_sha1 = "4af4a6c92b8ea07885b27d8536b81b855497f4eb",
)
maven_jar(
name = "bcpkix",
artifact = "org.bouncycastle:bcpkix-jdk15on:" + BOUNCYCASTLE_VER,
- sha1 = "45c36fb72fafb0b688c6af795e6cc803f6f79ee5",
- src_sha1 = "8bc5214401459bd91eea816b516079da38374e90",
+ sha1 = "f81e5af49571a9d5a109a88f239a73ce87055417",
+ src_sha1 = "42f9de53a91b20bc06e88482c57fd97e5a84250d",
)
diff --git a/lib/BUILD b/lib/BUILD
index 94427f6..6be9e57 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -97,7 +97,7 @@
java_library(
name = "jna",
visibility = [
- "//org.eclipse.jgit.ssh.apache.agent:__pkg__",
+ "//org.eclipse.jgit.ssh.apache.agent:__pkg__",
],
exports = ["@jna//jar"],
)
@@ -105,7 +105,7 @@
java_library(
name = "jna-platform",
visibility = [
- "//org.eclipse.jgit.ssh.apache.agent:__pkg__",
+ "//org.eclipse.jgit.ssh.apache.agent:__pkg__",
],
exports = ["@jna-platform//jar"],
)
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 9433658..0997570 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -5,13 +5,13 @@
Automatic-Module-Name: org.eclipse.jgit.ant.test
Bundle-SymbolicName: org.eclipse.jgit.ant.test
Bundle-Vendor: %Bundle-Vendor
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.ant.tasks;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.hamcrest.core;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index 6ad6415..ba473ef 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 10bfbd2..6003a31 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ant
Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)"
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)"
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.ant;version="6.0.1",
- org.eclipse.jgit.ant.tasks;version="6.0.1";
+Export-Package: org.eclipse.jgit.ant;version="6.1.1",
+ org.eclipse.jgit.ant.tasks;version="6.1.1";
uses:="org.apache.tools.ant,
org.apache.tools.ant.types"
diff --git a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
index c3ebfb3..d0dc5c8 100644
--- a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.ant - Sources
Bundle-SymbolicName: org.eclipse.jgit.ant.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ant;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ant;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index 4448f2e..a7f258b 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 62fe5a5..3fc8df1 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.archive
Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -13,17 +13,17 @@
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="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.osgi.framework;version="[1.3.0,2.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="6.0.1";
+Export-Package: org.eclipse.jgit.archive;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.api,
org.apache.commons.compress.archivers,
org.osgi.framework",
- org.eclipse.jgit.archive.internal;version="6.0.1";x-internal:=true
+ org.eclipse.jgit.archive.internal;version="6.1.1";x-internal:=true
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index deab2fa..8c7fd07 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: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 45f11da..12f3e68 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.archive</artifactId>
diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml
index 55c80c6..ac1d6bd 100644
--- a/org.eclipse.jgit.benchmarks/pom.xml
+++ b/org.eclipse.jgit.benchmarks/pom.xml
@@ -14,7 +14,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jgit</groupId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
<artifactId>org.eclipse.jgit.benchmarks</artifactId>
<packaging>jar</packaging>
diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml
index 63ead27..abc37ec 100644
--- a/org.eclipse.jgit.coverage/pom.xml
+++ b/org.eclipse.jgit.coverage/pom.xml
@@ -14,7 +14,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -27,88 +27,88 @@
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ant</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.archive</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.server</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs.server</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.pgm</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ui</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
</dependencies>
diff --git a/org.eclipse.jgit.gpg.bc.test/BUILD b/org.eclipse.jgit.gpg.bc.test/BUILD
index 35b125f..9e5813c 100644
--- a/org.eclipse.jgit.gpg.bc.test/BUILD
+++ b/org.eclipse.jgit.gpg.bc.test/BUILD
@@ -10,8 +10,8 @@
junit_tests(
name = "bc",
srcs = glob(["tst/**/*.java"]),
- resource_jars = [":tst_rsrc"],
tags = ["bc"],
+ runtime_deps = [":tst_rsrc"],
deps = [
"//lib:bcpg",
"//lib:bcprov",
diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
index d703432..bb9b393 100644
--- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.gpg.bc.test
Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -12,9 +12,9 @@
org.bouncycastle.openpgp.operator;version="[1.65.0,2.0.0)",
org.bouncycastle.openpgp.operator.jcajce;version="[1.65.0,2.0.0)",
org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)",
- org.eclipse.jgit.gpg.bc.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.gpg.bc.internal.keys;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.sha1;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.gpg.bc.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.sha1;version="[6.1.1,6.2.0)",
org.hamcrest;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.runner;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.gpg.bc.test/pom.xml b/org.eclipse.jgit.gpg.bc.test/pom.xml
index ad955b0..9568c68 100644
--- a/org.eclipse.jgit.gpg.bc.test/pom.xml
+++ b/org.eclipse.jgit.gpg.bc.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.gpg.bc.test</artifactId>
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
index 74e3305..534568d 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -3,10 +3,10 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.gpg.bc
Bundle-SymbolicName: org.eclipse.jgit.gpg.bc;singleton:=true
-Fragment-Host: org.eclipse.jgit;bundle-version="[6.0.1,6.1.0)"
+Fragment-Host: org.eclipse.jgit;bundle-version="[6.1.1,6.2.0)"
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: org.bouncycastle.asn1;version="[1.69.0,2.0.0)",
org.bouncycastle.asn1.cryptlib;version="[1.69.0,2.0.0)",
@@ -29,9 +29,9 @@
org.bouncycastle.util;version="[1.69.0,2.0.0)",
org.bouncycastle.util.encoders;version="[1.69.0,2.0.0)",
org.bouncycastle.util.io;version="[1.69.0,2.0.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.gpg.bc;version="6.0.1",
- org.eclipse.jgit.gpg.bc.internal;version="6.0.1";x-friends:="org.eclipse.jgit.gpg.bc.test",
- org.eclipse.jgit.gpg.bc.internal.keys;version="6.0.1";x-friends:="org.eclipse.jgit.gpg.bc.test"
+Export-Package: org.eclipse.jgit.gpg.bc;version="6.1.1",
+ org.eclipse.jgit.gpg.bc.internal;version="6.1.1";x-friends:="org.eclipse.jgit.gpg.bc.test",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="6.1.1";x-friends:="org.eclipse.jgit.gpg.bc.test"
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
index de4962b..20e2d01 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.gpg.bc - Sources
Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml
index 4bf82c6..138f4e8 100644
--- a/org.eclipse.jgit.gpg.bc/pom.xml
+++ b/org.eclipse.jgit.gpg.bc/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.gpg.bc</artifactId>
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index c51a87e..afcaa78 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.http.apache
Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
@@ -25,11 +25,11 @@
org.apache.http.impl.conn;version="[4.4.0,5.0.0)",
org.apache.http.params;version="[4.3.0,5.0.0)",
org.apache.http.ssl;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="6.0.1";
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="6.1.1";
uses:="org.apache.http.client,
org.eclipse.jgit.transport.http,
org.apache.http.entity,
diff --git a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
index 9d4f5f2..7b8e149 100644
--- a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.http.apache - Sources
Bundle-SymbolicName: org.eclipse.jgit.http.apache.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 6e5f260..bd35589 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/.settings/.api_filters b/org.eclipse.jgit.http.server/.settings/.api_filters
new file mode 100644
index 0000000..2c32c98
--- /dev/null
+++ b/org.eclipse.jgit.http.server/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.http.server" version="2">
+ <resource path="src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java" type="org.eclipse.jgit.http.server.UploadPackErrorHandler">
+ <filter id="1210056707">
+ <message_arguments>
+ <message_argument value="6.1.1"/>
+ <message_argument value="statusCodeForThrowable(Throwable)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 510c439..4bf66a2 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.http.server
Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.http.server;version="6.0.1",
- org.eclipse.jgit.http.server.glue;version="6.0.1";
+Export-Package: org.eclipse.jgit.http.server;version="6.1.1",
+ org.eclipse.jgit.http.server.glue;version="6.1.1";
uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="6.0.1";
+ org.eclipse.jgit.http.server.resolver;version="6.1.1";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.lib,
org.eclipse.jgit.transport,
@@ -18,14 +18,14 @@
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: javax.servlet;version="[2.5.0,5.0.0)",
javax.servlet.http;version="[2.5.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.parser;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.resolver;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)"
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)"
diff --git a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
index 7453cb8..2b47055 100644
--- a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.http.server - Sources
Bundle-SymbolicName: org.eclipse.jgit.http.server.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index b01c791..6a788e2 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -19,7 +19,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index 012f9a3..f1155dc 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -158,11 +158,11 @@ public static void sendError(HttpServletRequest req,
}
if (isInfoRefs(req)) {
- sendInfoRefsError(req, res, textForGit);
+ sendInfoRefsError(req, res, textForGit, httpStatus);
} else if (isUploadPack(req)) {
- sendUploadPackError(req, res, textForGit);
+ sendUploadPackError(req, res, textForGit, httpStatus);
} else if (isReceivePack(req)) {
- sendReceivePackError(req, res, textForGit);
+ sendReceivePackError(req, res, textForGit, httpStatus);
} else {
if (httpStatus < 400)
ServletUtils.consumeRequestBody(req);
@@ -171,29 +171,32 @@ public static void sendError(HttpServletRequest req,
}
private static void sendInfoRefsError(HttpServletRequest req,
- HttpServletResponse res, String textForGit) throws IOException {
+ HttpServletResponse res, String textForGit, int httpStatus)
+ throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
PacketLineOut pck = new PacketLineOut(buf);
String svc = req.getParameter("service");
pck.writeString("# service=" + svc + "\n");
pck.end();
pck.writeString("ERR " + textForGit);
- send(req, res, infoRefsResultType(svc), buf.toByteArray());
+ send(req, res, infoRefsResultType(svc), buf.toByteArray(), httpStatus);
}
private static void sendUploadPackError(HttpServletRequest req,
- HttpServletResponse res, String textForGit) throws IOException {
+ HttpServletResponse res, String textForGit, int httpStatus)
+ throws IOException {
// Do not use sideband. Sideband is acceptable only while packfile is
// being sent. Other places, like acknowledgement section, do not
// support sideband. Use an error packet.
ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
PacketLineOut pckOut = new PacketLineOut(buf);
writePacket(pckOut, textForGit);
- send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray());
+ send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray(), httpStatus);
}
private static void sendReceivePackError(HttpServletRequest req,
- HttpServletResponse res, String textForGit) throws IOException {
+ HttpServletResponse res, String textForGit, int httpStatus)
+ throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
PacketLineOut pckOut = new PacketLineOut(buf);
@@ -212,7 +215,7 @@ private static void sendReceivePackError(HttpServletRequest req,
writeSideBand(buf, textForGit);
else
writePacket(pckOut, textForGit);
- send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray());
+ send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray(), httpStatus);
}
private static boolean isReceivePackSideBand(HttpServletRequest req) {
@@ -246,9 +249,9 @@ private static void writePacket(PacketLineOut pckOut, String textForGit)
}
private static void send(HttpServletRequest req, HttpServletResponse res,
- String type, byte[] buf) throws IOException {
+ String type, byte[] buf, int httpStatus) throws IOException {
ServletUtils.consumeRequestBody(req);
- res.setStatus(HttpServletResponse.SC_OK);
+ res.setStatus(httpStatus);
res.setContentType(type);
res.setContentLength(buf.length);
try (OutputStream os = res.getOutputStream()) {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java
index 03be087..2aadbbc 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java
@@ -9,13 +9,19 @@
*/
package org.eclipse.jgit.http.server;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import org.eclipse.jgit.transport.UploadPack;
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
/**
* Handle git-upload-pack errors.
@@ -35,6 +41,24 @@
*/
public interface UploadPackErrorHandler {
/**
+ * Maps a thrown git related Exception to an appropriate HTTP status code.
+ *
+ * @param error
+ * The thrown Exception.
+ * @return the HTTP status code as an int
+ * @since 6.1.1
+ */
+ public static int statusCodeForThrowable(Throwable error) {
+ if (error instanceof ServiceNotEnabledException) {
+ return SC_FORBIDDEN;
+ }
+ if (error instanceof PackProtocolException) {
+ // Internal git errors are not errors from an HTTP standpoint.
+ return SC_OK;
+ }
+ return SC_INTERNAL_SERVER_ERROR;
+ }
+ /**
* @param req
* The HTTP request
* @param rsp
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
index c4f845e..b0a07f1 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
@@ -11,7 +11,6 @@
package org.eclipse.jgit.http.server;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
-import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static javax.servlet.http.HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
import static org.eclipse.jgit.http.server.GitSmartHttpTools.UPLOAD_PACK;
@@ -22,6 +21,7 @@
import static org.eclipse.jgit.http.server.ServletUtils.consumeRequestBody;
import static org.eclipse.jgit.http.server.ServletUtils.getInputStream;
import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
+import static org.eclipse.jgit.http.server.UploadPackErrorHandler.statusCodeForThrowable;
import static org.eclipse.jgit.util.HttpSupport.HDR_USER_AGENT;
import java.io.IOException;
@@ -169,6 +169,7 @@ public void doPost(HttpServletRequest req, HttpServletResponse rsp)
UploadPackRunnable r = () -> {
UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
+ // to be explicitly closed by caller
@SuppressWarnings("resource")
SmartOutputStream out = new SmartOutputStream(req, rsp, false) {
@Override
@@ -217,9 +218,12 @@ private void defaultUploadPackHandler(HttpServletRequest req,
log(up.getRepository(), e);
if (!rsp.isCommitted()) {
rsp.reset();
- String msg = e instanceof PackProtocolException ? e.getMessage()
- : null;
- sendError(req, rsp, SC_INTERNAL_SERVER_ERROR, msg);
+ String msg = null;
+ if (e instanceof PackProtocolException
+ || e instanceof ServiceNotEnabledException) {
+ msg = e.getMessage();
+ }
+ sendError(req, rsp, statusCodeForThrowable(e), msg);
}
}
}
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 3a6517c..4150bdb 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.http.test
Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -26,26 +26,26 @@
org.eclipse.jetty.util.log;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.security;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.thread;version="[10.0.0,11.0.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.http.server;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.http.server.glue;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.http.server.resolver;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http.apache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.resolver;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.http.server;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.http.server.glue;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.http.server.resolver;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http.apache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.hamcrest;version="[1.1.0,3.0.0)",
org.hamcrest.core;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index 7694c44..336f43b 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -18,7 +18,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
index db9f2ae..20de256 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
@@ -97,6 +97,7 @@ public ReceivePack create(HttpServletRequest req, Repository db)
server.setUp();
remoteRepository = src.getRepository();
+ addRepoToClose(remoteRepository);
remoteURI = toURIish(app, srcName);
StoredConfig cfg = remoteRepository.getConfig();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
index df093c1..3438c52 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
@@ -23,6 +23,7 @@
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
+import java.text.MessageFormat;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -308,7 +309,10 @@ public void testListRemote_Smart_UploadPackDisabled() throws Exception {
fail("connection opened even though service disabled");
} catch (TransportException err) {
String exp = smartAuthNoneURI + ": "
- + JGitText.get().serviceNotEnabledNoName;
+ + MessageFormat.format(
+ JGitText.get().serviceNotPermitted,
+ smartAuthNoneURI.toString() + "/",
+ "git-upload-pack");
assertEquals(exp, err.getMessage());
}
}
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java
index 9ffa19e..000eecd 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java
@@ -90,6 +90,7 @@ public ReceivePack create(HttpServletRequest req, Repository db)
server.setUp();
remoteRepository = src.getRepository();
+ addRepoToClose(remoteRepository);
remoteURI = toURIish(app, srcName);
StoredConfig cfg = remoteRepository.getConfig();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index 887e970..b9b10b4 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -57,7 +57,7 @@
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.TransportConfigCallback;
-import org.eclipse.jgit.errors.RemoteRepositoryException;
+import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.http.server.GitServlet;
@@ -496,8 +496,9 @@ public void testListRemote_BadName() throws IOException, URISyntaxException {
try {
t.openFetch();
fail("fetch connection opened");
- } catch (RemoteRepositoryException notFound) {
- assertEquals(uri + ": Git repository not found",
+ } catch (NoRemoteRepositoryException notFound) {
+ assertEquals(uri + ": " + uri
+ + "/info/refs?service=git-upload-pack not found: Not Found",
notFound.getMessage());
}
}
@@ -510,7 +511,7 @@ public void testListRemote_BadName() throws IOException, URISyntaxException {
assertEquals(join(uri, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-upload-pack", info.getParameter("service"));
- assertEquals(200, info.getStatus());
+ assertEquals(404, info.getStatus());
assertEquals("application/x-git-upload-pack-advertisement",
info.getResponseHeader(HDR_CONTENT_TYPE));
}
@@ -538,6 +539,7 @@ public void testFetchBySHA1Unreachable() throws Exception {
assertTrue(e.getMessage().contains(
"want " + unreachableCommit.name() + " not valid"));
}
+ assertLastRequestStatusCode(200);
}
@Test
@@ -560,6 +562,7 @@ protected Map<String, Ref> getAdvertisedRefs(Repository repository,
assertTrue(
e.getMessage().contains("want " + A.name() + " not valid"));
}
+ assertLastRequestStatusCode(200);
}
@Test
@@ -916,6 +919,7 @@ public void testInitialClone_RedirectOnPostForbidden() throws Exception {
} catch (TransportException e) {
assertTrue(e.getMessage().contains("301"));
}
+ assertLastRequestStatusCode(301);
}
@Test
@@ -934,6 +938,7 @@ public void testInitialClone_RedirectForbidden() throws Exception {
assertTrue(
e.getMessage().contains("http.followRedirects is false"));
}
+ assertLastRequestStatusCode(301);
}
private void assertFetchRequests(List<AccessEvent> requests, int index) {
@@ -1607,6 +1612,7 @@ public void testInvalidWant() throws Exception {
assertTrue(err.getMessage()
.contains("want " + id.name() + " not valid"));
}
+ assertLastRequestStatusCode(200);
}
@Test
@@ -1650,7 +1656,7 @@ public void testFetch_RefsUnreadableOnUpload() throws Exception {
fail("Successfully served ref with value " + c.getRef(master));
} catch (TransportException err) {
assertTrue("Unexpected exception message " + err.getMessage(),
- err.getMessage().contains("Internal server error"));
+ err.getMessage().contains("Server Error"));
}
} finally {
noRefServer.tearDown();
@@ -1821,6 +1827,11 @@ public void testPush_ChunkedEncoding() throws Exception {
.getResponseHeader(HDR_CONTENT_TYPE));
}
+ private void assertLastRequestStatusCode(int statusCode) {
+ List<AccessEvent> requests = getRequests();
+ assertEquals(statusCode, requests.get(requests.size() - 1).getStatus());
+ }
+
private void enableReceivePack() throws IOException {
final StoredConfig cfg = remoteRepository.getConfig();
cfg.setBoolean("http", null, "receivepack", true);
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index c21f835..d035072 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.junit.http
Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
@@ -21,17 +21,17 @@
org.eclipse.jetty.util.log;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.security;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.ssl;version="[10.0.0,11.0.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.http.server;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.resolver;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.http.server;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.1.1,6.2.0)",
org.junit;version="[4.13,5.0.0)",
org.slf4j.helpers;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="6.0.1";
+Export-Package: org.eclipse.jgit.junit.http;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.junit,
javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
index 98fde06..19142c5 100644
--- a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.junit.http - Sources
Bundle-SymbolicName: org.eclipse.jgit.junit.http.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index b66991f..d883e03 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
index 3e7c84f..877b918 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java
@@ -22,6 +22,7 @@
import java.util.Set;
import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
@@ -80,7 +81,9 @@ protected AppServer createServer() {
*/
protected TestRepository<Repository> createTestRepository()
throws IOException {
- return new TestRepository<>(createBareRepository());
+ final FileRepository repository = createBareRepository();
+ addRepoToClose(repository);
+ return new TestRepository<>(repository);
}
/**
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 8d629ed..60858d8 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -3,46 +3,46 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.junit.ssh
Bundle-SymbolicName: org.eclipse.jgit.junit.ssh
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Import-Package: org.apache.sshd.common;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.config.keys;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.file.virtualfs;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.helpers;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.io;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.kex;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.keyprovider;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.session;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.signature;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.buffer;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.logging;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.security;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.threads;version="[2.7.0,2.8.0)",
- org.apache.sshd.core;version="[2.7.0,2.8.0)",
- org.apache.sshd.server;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.auth;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.auth.gss;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.auth.keyboard;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.auth.password;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.command;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.session;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.shell;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.subsystem;version="[2.7.0,2.8.0)",
- org.apache.sshd.sftp;version="[2.7.0,2.8.0)",
- org.apache.sshd.sftp.server;version="[2.7.0,2.8.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+Import-Package: org.apache.sshd.common;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.config.keys;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.file.virtualfs;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.helpers;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.io;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.kex;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.keyprovider;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.session;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.signature;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.buffer;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.logging;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.security;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.threads;version="[2.8.0,2.9.0)",
+ org.apache.sshd.core;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.auth;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.auth.gss;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.auth.keyboard;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.auth.password;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.command;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.session;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.shell;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.subsystem;version="[2.8.0,2.9.0)",
+ org.apache.sshd.sftp;version="[2.8.0,2.9.0)",
+ org.apache.sshd.sftp.server;version="[2.8.0,2.9.0)",
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.experimental.theories;version="[4.13,5.0.0)",
org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit.ssh;version="6.0.1"
+Export-Package: org.eclipse.jgit.junit.ssh;version="6.1.1"
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
index 7132b5b..41246bc 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.junit.ssh - Sources
Bundle-SymbolicName: org.eclipse.jgit.junit.ssh.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index 76bdca1..07d0218 100644
--- a/org.eclipse.jgit.junit.ssh/pom.xml
+++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.ssh</artifactId>
@@ -55,6 +55,16 @@
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-sftp</artifactId>
<version>${apache-sshd-version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-common</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
diff --git a/org.eclipse.jgit.junit/.settings/.api_filters b/org.eclipse.jgit.junit/.settings/.api_filters
new file mode 100644
index 0000000..a17a72f
--- /dev/null
+++ b/org.eclipse.jgit.junit/.settings/.api_filters
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit.junit" version="2">
+ <resource path="src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java" type="org.eclipse.jgit.junit.LocalDiskRepositoryTestCase">
+ <filter id="336658481">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.junit.LocalDiskRepositoryTestCase"/>
+ <message_argument value="currentTest"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="6.0.1"/>
+ <message_argument value="currentTest"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 1f021da..7a3b200 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,35 +3,35 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.junit
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Import-Package: org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.dircache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.pack;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.merge;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="6.0.1",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.io;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.time;version="[6.0.1,6.1.0)",
+Import-Package: org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.dircache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.merge;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="6.1.1",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.time;version="[6.1.1,6.2.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.rules;version="[4.13,5.0.0)",
org.junit.runner;version="[4.13,5.0.0)",
org.junit.runners;version="[4.13,5.0.0)",
org.junit.runners.model;version="[4.13,5.0.0)",
org.slf4j;version="[1.7.0,2.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="6.0.1";
+Export-Package: org.eclipse.jgit.junit;version="6.1.1";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
@@ -44,4 +44,4 @@
org.junit.runners.model,
org.junit.runner,
org.eclipse.jgit.util.time",
- org.eclipse.jgit.junit.time;version="6.0.1";uses:="org.eclipse.jgit.util.time"
+ org.eclipse.jgit.junit.time;version="6.1.1";uses:="org.eclipse.jgit.util.time"
diff --git a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
index 156e59a..25876c7 100644
--- a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.junit - Sources
Bundle-SymbolicName: org.eclipse.jgit.junit.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index ef2b946..2c260e2 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -19,7 +19,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index 494d2f3..59662ce 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
@@ -45,6 +45,8 @@
import org.eclipse.jgit.util.SystemReader;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
/**
* JUnit TestCase with specialized support for temporary local repository.
@@ -84,18 +86,35 @@ public abstract class LocalDiskRepositoryTestCase {
private File tmp;
/**
+ * The current test name.
+ *
+ * @since 6.0.1
+ */
+ @Rule
+ public TestName currentTest = new TestName();
+
+ private String getTestName() {
+ String name = currentTest.getMethodName();
+ name = name.replaceAll("[^a-zA-Z0-9]", "_");
+ name = name.replaceAll("__+", "_");
+ if (name.startsWith("_")) {
+ name = name.substring(1);
+ }
+ return name;
+ }
+
+ /**
* Setup test
*
* @throws Exception
*/
@Before
public void setUp() throws Exception {
- tmp = File.createTempFile("jgit_test_", "_tmp");
+ tmp = File.createTempFile("jgit_" + getTestName() + '_', "_tmp");
CleanupThread.deleteOnShutdown(tmp);
if (!tmp.delete() || !tmp.mkdir()) {
throw new IOException("Cannot create " + tmp);
}
-
mockSystemReader = new MockSystemReader();
SystemReader.setInstance(mockSystemReader);
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 b2a82c2..cbb8135 100644
--- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs.server.test
Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -26,24 +26,24 @@
org.eclipse.jetty.util.log;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.security;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.thread;version="[10.0.0,11.0.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.server;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.server.fs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.test;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.server;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.test;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.hamcrest.core;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.rules;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml
index ef8751e..1bab620 100644
--- a/org.eclipse.jgit.lfs.server.test/pom.xml
+++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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/PushTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/PushTest.java
index 70c0463..06708b3 100644
--- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/PushTest.java
+++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/PushTest.java
@@ -11,6 +11,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import java.io.InputStream;
import java.nio.file.Files;
@@ -29,6 +30,7 @@
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
@@ -128,4 +130,18 @@ public void testPushSimple() throws Exception {
server.getRequests().toString());
}
+ @Test
+ public void testDeleteBranch() throws Exception {
+ String branch = "new-branch";
+ git.branchCreate().setName(branch).call();
+
+ String destRef = Constants.R_HEADS + branch;
+ git.push().setRefSpecs(new RefSpec().setSource(branch).setDestination(destRef)).call();
+
+ // Should not fail on push.
+ git.branchDelete().setBranchNames(branch).setForce(true).call();
+ git.push().setRefSpecs(new RefSpec().setSource(null).setDestination(destRef)).call();
+
+ assertTrue(server.getRequests().isEmpty());
+ }
}
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index 3a4448b..cd8bde3 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs.server
Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.lfs.server;version="6.0.1";
+Export-Package: org.eclipse.jgit.lfs.server;version="6.1.1";
uses:="javax.servlet.http,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="6.0.1";
+ org.eclipse.jgit.lfs.server.fs;version="6.1.1";
uses:="javax.servlet,
javax.servlet.http,
org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="6.0.1";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="6.0.1";
+ org.eclipse.jgit.lfs.server.internal;version="6.1.1";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="6.1.1";
uses:="org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib"
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -24,15 +24,15 @@
javax.servlet.annotation;version="[3.1.0,5.0.0)",
javax.servlet.http;version="[3.1.0,5.0.0)",
org.apache.http;version="[4.3.0,5.0.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http.apache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http.apache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
index 5011a22..5a5b23a 100644
--- a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.lfs.server - Sources
Bundle-SymbolicName: org.eclipse.jgit.lfs.server.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index c2d6596..ae27153 100644
--- a/org.eclipse.jgit.lfs.server/pom.xml
+++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
index b870794..e3c0af8 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -3,24 +3,27 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs.test
Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Import-Package: org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.attributes;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+Import-Package: org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.attributes;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.hamcrest.core;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.runner;version="[4.13,5.0.0)",
org.junit.runners;version="[4.13,5.0.0)"
-Export-Package: org.eclipse.jgit.lfs.test;version="6.0.1";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="6.1.1";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 a88ca94..1d782e6 100644
--- a/org.eclipse.jgit.lfs.test/pom.xml
+++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsConfigGitTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsConfigGitTest.java
new file mode 100644
index 0000000..98a0712
--- /dev/null
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsConfigGitTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2022, Matthias Fromme <mfromme@dspace.de>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lfs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.ResetCommand.ResetType;
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lfs.internal.LfsConnectionFactory;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.http.HttpConnection;
+import org.eclipse.jgit.util.HttpSupport;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test if the lfs config is used in the correct way during checkout.
+ *
+ * Two lfs-files are created, one that comes before .gitattributes and
+ * .lfsconfig in git order (".aaa.txt") and one that comes after ("zzz.txt").
+ *
+ * During checkout/reset it is tested if the correct version of the lfs config
+ * is used.
+ *
+ * TODO: The current behavior seems a little bit strange/unintuitive. Some files
+ * are checked out before and some after the config files. This leads to the
+ * behavior, that during a single command the config changes. Since this seems
+ * to be the same way in native git, the behavior is accepted for now.
+ *
+ */
+public class LfsConfigGitTest extends RepositoryTestCase {
+
+ private static final String SMUDGE_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+ + Constants.ATTR_FILTER_DRIVER_PREFIX
+ + org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_SMUDGE;
+
+ private static final String LFS_SERVER_URI1 = "https://lfs.server1/test/uri";
+
+ private static final String EXPECTED_SERVER_URL1 = LFS_SERVER_URI1
+ + Protocol.OBJECTS_LFS_ENDPOINT;
+
+ private static final String LFS_SERVER_URI2 = "https://lfs.server2/test/uri";
+
+ private static final String EXPECTED_SERVER_URL2 = LFS_SERVER_URI2
+ + Protocol.OBJECTS_LFS_ENDPOINT;
+
+ private static final String LFS_SERVER_URI3 = "https://lfs.server3/test/uri";
+
+ private static final String EXPECTED_SERVER_URL3 = LFS_SERVER_URI3
+ + Protocol.OBJECTS_LFS_ENDPOINT;
+
+ private static final String FAKE_LFS_POINTER1 = "version https://git-lfs.github.com/spec/v1\n"
+ + "oid sha256:6ce9fab52ee9a6c4c097def4e049c6acdeba44c99d26e83ba80adec1473c9b2d\n"
+ + "size 253952\n";
+
+ private static final String FAKE_LFS_POINTER2 = "version https://git-lfs.github.com/spec/v1\n"
+ + "oid sha256:a4b711cd989863ae2038758a62672138347abbbae4076a7ad3a545fda7d08f82\n"
+ + "size 67072\n";
+
+ private static List<String> checkoutURLs = new ArrayList<>();
+
+ static class SmudgeFilterMock extends FilterCommand {
+ public SmudgeFilterMock(Repository db, InputStream in,
+ OutputStream out) throws IOException {
+ super(in, out);
+ HttpConnection lfsServerConn = LfsConnectionFactory.getLfsConnection(db,
+ HttpSupport.METHOD_POST, Protocol.OPERATION_DOWNLOAD);
+ checkoutURLs.add(lfsServerConn.getURL().toString());
+ }
+
+ @Override
+ public int run() throws IOException {
+ // Stupid no impl
+ in.transferTo(out);
+ return -1;
+ }
+ }
+
+ @BeforeClass
+ public static void installLfs() {
+ FilterCommandRegistry.register(SMUDGE_NAME, SmudgeFilterMock::new);
+ }
+
+ @AfterClass
+ public static void removeLfs() {
+ FilterCommandRegistry.unregister(SMUDGE_NAME);
+ }
+
+ private Git git;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+ // commit something
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ // prepare the config for LFS
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "lfs", "smudge", SMUDGE_NAME);
+ config.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF, "false");
+ config.save();
+
+ fileBefore = null;
+ fileAfter = null;
+ configFile = null;
+ gitAttributesFile = null;
+ }
+
+ File fileBefore;
+
+ File fileAfter;
+
+ File configFile;
+
+ File gitAttributesFile;
+
+ private void createLfsFiles(String lfsPointer) throws Exception {
+ /*
+ * FileNames ".aaa.txt" and "zzz.txt" seem to be sufficient to get the
+ * desired checkout order before and after ".lfsconfig", at least in a
+ * number of manual tries. Since the files to checkout are contained in
+ * a set (see DirCacheCheckout::doCheckout) the order cannot be
+ * guaranteed.
+ */
+
+ //File to be checked out before lfs config
+ String fileNameBefore = ".aaa.txt";
+ fileBefore = writeTrashFile(fileNameBefore, lfsPointer);
+ git.add().addFilepattern(fileNameBefore).call();
+
+ // File to be checked out after lfs config
+ String fileNameAfter = "zzz.txt";
+ fileAfter = writeTrashFile(fileNameAfter, lfsPointer);
+ git.add().addFilepattern(fileNameAfter).call();
+
+ git.commit().setMessage("Commit LFS Pointer files").call();
+ }
+
+
+ private String addLfsConfigFiles(String lfsServerUrl) throws Exception {
+ // Add config files to the repo
+ String lfsConfig1 = createLfsConfig(lfsServerUrl);
+ git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
+ // Modify gitattributes on second call, to force checkout too.
+ if (gitAttributesFile == null) {
+ gitAttributesFile = writeTrashFile(".gitattributes",
+ "*.txt filter=lfs");
+ } else {
+ gitAttributesFile = writeTrashFile(".gitattributes",
+ "*.txt filter=lfs\n");
+ }
+
+ git.add().addFilepattern(".gitattributes").call();
+ git.commit().setMessage("Commit config files").call();
+ return lfsConfig1;
+ }
+
+ private String createLfsConfig(String lfsServerUrl) throws IOException {
+ String lfsConfig1 = "[lfs]\n url = " + lfsServerUrl;
+ configFile = writeTrashFile(Constants.DOT_LFS_CONFIG, lfsConfig1);
+ return lfsConfig1;
+ }
+
+ @Test
+ public void checkoutLfsObjects_reset() throws Exception {
+ createLfsFiles(FAKE_LFS_POINTER1);
+ String lfsConfig1 = addLfsConfigFiles(LFS_SERVER_URI1);
+
+ // Delete files to force action on reset
+ assertTrue(configFile.delete());
+ assertTrue(fileBefore.delete());
+ assertTrue(fileAfter.delete());
+
+ assertTrue(gitAttributesFile.delete());
+
+ // create config file with different url
+ createLfsConfig(LFS_SERVER_URI3);
+
+ checkoutURLs.clear();
+ git.reset().setMode(ResetType.HARD).call();
+
+ checkFile(configFile, lfsConfig1);
+ checkFile(fileBefore, FAKE_LFS_POINTER1);
+ checkFile(fileAfter, FAKE_LFS_POINTER1);
+
+ assertEquals(2, checkoutURLs.size());
+ // TODO: Should may be EXPECTED_SERVR_URL1
+ assertEquals(EXPECTED_SERVER_URL3, checkoutURLs.get(0));
+ assertEquals(EXPECTED_SERVER_URL1, checkoutURLs.get(1));
+ }
+
+ @Test
+ public void checkoutLfsObjects_BranchSwitch() throws Exception {
+ // Create a new branch "URL1" and add config files
+ git.checkout().setCreateBranch(true).setName("URL1").call();
+
+ createLfsFiles(FAKE_LFS_POINTER1);
+ String lfsConfig1 = addLfsConfigFiles(LFS_SERVER_URI1);
+
+ // Create a second new branch "URL2" and add config files
+ git.checkout().setCreateBranch(true).setName("URL2").call();
+
+ createLfsFiles(FAKE_LFS_POINTER2);
+ String lfsConfig2 = addLfsConfigFiles(LFS_SERVER_URI2);
+
+ checkFile(configFile, lfsConfig2);
+ checkFile(fileBefore, FAKE_LFS_POINTER2);
+ checkFile(fileAfter, FAKE_LFS_POINTER2);
+
+ checkoutURLs.clear();
+ git.checkout().setName("URL1").call();
+
+ checkFile(configFile, lfsConfig1);
+ checkFile(fileBefore, FAKE_LFS_POINTER1);
+ checkFile(fileAfter, FAKE_LFS_POINTER1);
+
+ assertEquals(2, checkoutURLs.size());
+ // TODO: Should may be EXPECTED_SERVR_URL1
+ assertEquals(EXPECTED_SERVER_URL2, checkoutURLs.get(0));
+ assertEquals(EXPECTED_SERVER_URL1, checkoutURLs.get(1));
+
+ checkoutURLs.clear();
+ git.checkout().setName("URL2").call();
+
+ checkFile(configFile, lfsConfig2);
+ checkFile(fileBefore, FAKE_LFS_POINTER2);
+ checkFile(fileAfter, FAKE_LFS_POINTER2);
+
+ assertEquals(2, checkoutURLs.size());
+ // TODO: Should may be EXPECTED_SERVR_URL2
+ assertEquals(EXPECTED_SERVER_URL1, checkoutURLs.get(0));
+ assertEquals(EXPECTED_SERVER_URL2, checkoutURLs.get(1));
+ }
+
+ @Test
+ public void checkoutLfsObjects_BranchSwitch_ModifiedLocal()
+ throws Exception {
+
+ // Create a new branch "URL1" and add config files
+ git.checkout().setCreateBranch(true).setName("URL1").call();
+
+ createLfsFiles(FAKE_LFS_POINTER1);
+ addLfsConfigFiles(LFS_SERVER_URI1);
+
+ // Create a second new branch "URL2" and add config files
+ git.checkout().setCreateBranch(true).setName("URL2").call();
+
+ createLfsFiles(FAKE_LFS_POINTER2);
+ addLfsConfigFiles(LFS_SERVER_URI1);
+
+ // create config file with different url
+ assertTrue(configFile.delete());
+ String lfsConfig3 = createLfsConfig(LFS_SERVER_URI3);
+
+ checkFile(configFile, lfsConfig3);
+ checkFile(fileBefore, FAKE_LFS_POINTER2);
+ checkFile(fileAfter, FAKE_LFS_POINTER2);
+
+ checkoutURLs.clear();
+ git.checkout().setName("URL1").call();
+
+ checkFile(fileBefore, FAKE_LFS_POINTER1);
+ checkFile(fileAfter, FAKE_LFS_POINTER1);
+ checkFile(configFile, lfsConfig3);
+
+ assertEquals(2, checkoutURLs.size());
+
+ assertEquals(EXPECTED_SERVER_URL3, checkoutURLs.get(0));
+ assertEquals(EXPECTED_SERVER_URL3, checkoutURLs.get(1));
+
+ checkoutURLs.clear();
+ git.checkout().setName("URL2").call();
+
+ checkFile(fileBefore, FAKE_LFS_POINTER2);
+ checkFile(fileAfter, FAKE_LFS_POINTER2);
+ checkFile(configFile, lfsConfig3);
+
+ assertEquals(2, checkoutURLs.size());
+ assertEquals(EXPECTED_SERVER_URL3, checkoutURLs.get(0));
+ assertEquals(EXPECTED_SERVER_URL3, checkoutURLs.get(1));
+ }
+}
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java
index 8964310..3e83c8e 100644
--- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsGitTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2021, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -68,6 +68,27 @@ public void setUp() throws Exception {
}
@Test
+ public void testBranchSwitch() throws Exception {
+ git.branchCreate().setName("abranch").call();
+ git.checkout().setName("abranch").call();
+ File aFile = writeTrashFile("a.bin", "aaa");
+ writeTrashFile(".gitattributes", "a.bin filter=lfs");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("acommit").call();
+ git.checkout().setName("master").call();
+ git.branchCreate().setName("bbranch").call();
+ git.checkout().setName("bbranch").call();
+ File bFile = writeTrashFile("b.bin", "bbb");
+ writeTrashFile(".gitattributes", "b.bin filter=lfs");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("bcommit").call();
+ git.checkout().setName("abranch").call();
+ checkFile(aFile, "aaa");
+ git.checkout().setName("bbranch").call();
+ checkFile(bFile, "bbb");
+ }
+
+ @Test
public void checkoutNonLfsPointer() throws Exception {
String content = "size_t\nsome_function(void* ptr);\n";
File smallFile = writeTrashFile("Test.txt", content);
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java
new file mode 100644
index 0000000..badcb7d
--- /dev/null
+++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2022 Nail Samatov <sanail@yandex.ru> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lfs.internal;
+
+import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.RemoteAddCommand;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lfs.CleanFilter;
+import org.eclipse.jgit.lfs.Protocol;
+import org.eclipse.jgit.lfs.SmudgeFilter;
+import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.http.HttpConnection;
+import org.eclipse.jgit.util.HttpSupport;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class LfsConnectionFactoryTest extends RepositoryTestCase {
+
+ private static final String SMUDGE_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+ + Constants.ATTR_FILTER_DRIVER_PREFIX
+ + org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_SMUDGE;
+
+ private static final String CLEAN_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+ + Constants.ATTR_FILTER_DRIVER_PREFIX
+ + org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_CLEAN;
+
+ private final static String LFS_SERVER_URL1 = "https://lfs.server1/test/uri";
+
+ private final static String LFS_SERVER_URL2 = "https://lfs.server2/test/uri";
+
+ private final static String ORIGIN_URL = "https://git.server/test/uri";
+
+ private Git git;
+
+ @BeforeClass
+ public static void installLfs() {
+ FilterCommandRegistry.register(SMUDGE_NAME, SmudgeFilter.FACTORY);
+ FilterCommandRegistry.register(CLEAN_NAME, CleanFilter.FACTORY);
+ }
+
+ @AfterClass
+ public static void removeLfs() {
+ FilterCommandRegistry.unregister(SMUDGE_NAME);
+ FilterCommandRegistry.unregister(CLEAN_NAME);
+ }
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+
+ // Just to have a non empty repo
+ writeTrashFile("Test.txt", "Hello world from the LFS Factory Test");
+ git.add().addFilepattern("Test.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
+
+ @Test
+ public void lfsUrlFromRemoteUrlWithDotGit() throws Exception {
+ addRemoteUrl("https://localhost/repo.git");
+ checkLfsUrl("https://localhost/repo.git/info/lfs");
+ }
+
+ @Test
+ public void lfsUrlFromRemoteUrlWithoutDotGit() throws Exception {
+ addRemoteUrl("https://localhost/repo");
+ checkLfsUrl("https://localhost/repo.git/info/lfs");
+ }
+
+ @Test
+ public void lfsUrlFromLocalConfig() throws Exception {
+ addRemoteUrl("https://localhost/repo");
+
+ StoredConfig cfg = ((Repository) db).getConfig();
+ cfg.setString(ConfigConstants.CONFIG_SECTION_LFS,
+ null,
+ ConfigConstants.CONFIG_KEY_URL,
+ "https://localhost/repo/lfs");
+ cfg.save();
+
+ checkLfsUrl("https://localhost/repo/lfs");
+ }
+
+ @Test
+ public void lfsUrlFromOriginConfig() throws Exception {
+ addRemoteUrl("https://localhost/repo");
+
+ StoredConfig cfg = ((Repository) db).getConfig();
+ cfg.setString(ConfigConstants.CONFIG_SECTION_LFS,
+ org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME,
+ ConfigConstants.CONFIG_KEY_URL,
+ "https://localhost/repo/lfs");
+ cfg.save();
+
+ checkLfsUrl("https://localhost/repo/lfs");
+ }
+
+ @Test
+ public void lfsUrlNotConfigured() throws Exception {
+ assertThrows(LfsConfigInvalidException.class,
+ () -> LfsConnectionFactory.getLfsConnection(db,
+ HttpSupport.METHOD_POST, Protocol.OPERATION_DOWNLOAD));
+ }
+
+ @Test
+ public void checkGetLfsConnection_lfsurl_lfsconfigFromWorkingDir()
+ throws Exception {
+ writeLfsConfig();
+ checkLfsUrl(LFS_SERVER_URL1);
+ }
+
+ @Test
+ public void checkGetLfsConnection_lfsurl_lfsconfigFromIndex()
+ throws Exception {
+ writeLfsConfig();
+ git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
+ deleteTrashFile(Constants.DOT_LFS_CONFIG);
+ checkLfsUrl(LFS_SERVER_URL1);
+ }
+
+ @Test
+ public void checkGetLfsConnection_lfsurl_lfsconfigFromHEAD()
+ throws Exception {
+ writeLfsConfig();
+ git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
+ git.commit().setMessage("Commit LFS Config").call();
+
+ /*
+ * reading .lfsconfig from HEAD seems only testable using a bare repo,
+ * since otherwise working tree or index are used
+ */
+ File directory = createTempDirectory("testBareRepo");
+ try (Repository bareRepoDb = Git.cloneRepository()
+ .setDirectory(directory)
+ .setURI(db.getDirectory().toURI().toString()).setBare(true)
+ .call().getRepository()) {
+
+ checkLfsUrl(LFS_SERVER_URL1);
+ }
+ }
+
+ @Test
+ public void checkGetLfsConnection_remote_lfsconfigFromWorkingDir()
+ throws Exception {
+ addRemoteUrl(ORIGIN_URL);
+ writeLfsConfig(LFS_SERVER_URL1, "lfs", DEFAULT_REMOTE_NAME, "url");
+ checkLfsUrl(LFS_SERVER_URL1);
+ }
+
+ /**
+ * Test the config file precedence.
+ *
+ * Checking only with the local repository config is sufficient since from
+ * that point the "normal" precedence is used.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void checkGetLfsConnection_ConfigFilePrecedence_lfsconfigFromWorkingDir()
+ throws Exception {
+ writeLfsConfig();
+ checkLfsUrl(LFS_SERVER_URL1);
+
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString(ConfigConstants.CONFIG_SECTION_LFS, null,
+ ConfigConstants.CONFIG_KEY_URL, LFS_SERVER_URL2);
+ config.save();
+
+ checkLfsUrl(LFS_SERVER_URL2);
+ }
+
+ @Test
+ public void checkGetLfsConnection_InvalidLfsConfig_WorkingDir()
+ throws Exception {
+ writeInvalidLfsConfig();
+ LfsConfigInvalidException actualException = assertThrows(
+ LfsConfigInvalidException.class, () -> {
+ LfsConnectionFactory.getLfsConnection(db, HttpSupport.METHOD_POST,
+ Protocol.OPERATION_DOWNLOAD);
+ });
+ assertTrue(getStackTrace(actualException)
+ .contains("Invalid line in config file"));
+ }
+
+ @Test
+ public void checkGetLfsConnection_InvalidLfsConfig_Index()
+ throws Exception {
+ writeInvalidLfsConfig();
+ git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
+ deleteTrashFile(Constants.DOT_LFS_CONFIG);
+ LfsConfigInvalidException actualException = assertThrows(
+ LfsConfigInvalidException.class, () -> {
+ LfsConnectionFactory.getLfsConnection(db, HttpSupport.METHOD_POST,
+ Protocol.OPERATION_DOWNLOAD);
+ });
+ assertTrue(getStackTrace(actualException)
+ .contains("Invalid line in config file"));
+ }
+
+ @Test
+ public void checkGetLfsConnection_InvalidLfsConfig_HEAD() throws Exception {
+ writeInvalidLfsConfig();
+ git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
+ git.commit().setMessage("Commit LFS Config").call();
+
+ /*
+ * reading .lfsconfig from HEAD seems only testable using a bare repo,
+ * since otherwise working tree or index are used
+ */
+ File directory = createTempDirectory("testBareRepo");
+ try (Repository bareRepoDb = Git.cloneRepository()
+ .setDirectory(directory)
+ .setURI(db.getDirectory().toURI().toString()).setBare(true)
+ .call().getRepository()) {
+ LfsConfigInvalidException actualException = assertThrows(
+ LfsConfigInvalidException.class,
+ () -> {
+ LfsConnectionFactory.getLfsConnection(db,
+ HttpSupport.METHOD_POST,
+ Protocol.OPERATION_DOWNLOAD);
+ });
+ assertTrue(getStackTrace(actualException)
+ .contains("Invalid line in config file"));
+ }
+ }
+
+ private void addRemoteUrl(String remotUrl) throws Exception {
+ RemoteAddCommand add = git.remoteAdd();
+ add.setUri(new URIish(remotUrl));
+ add.setName(org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME);
+ add.call();
+ }
+
+ /**
+ * Returns the stack trace of the provided exception as string
+ *
+ * @param actualException
+ * @return The exception stack trace as string
+ */
+ private String getStackTrace(Exception actualException) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ actualException.printStackTrace(pw);
+ return sw.toString();
+ }
+
+ private void writeLfsConfig() throws IOException {
+ writeLfsConfig(LFS_SERVER_URL1, "lfs", "url");
+ }
+
+ private void writeLfsConfig(String lfsUrl, String section, String name)
+ throws IOException {
+ writeLfsConfig(lfsUrl, section, null, name);
+ }
+
+ /*
+ * Write simple lfs config with single entry. Do not use FileBasedConfig to
+ * avoid introducing new dependency (for now).
+ */
+ private void writeLfsConfig(String lfsUrl, String section,
+ String subsection, String name) throws IOException {
+ StringBuilder config = new StringBuilder();
+ config.append("[");
+ config.append(section);
+ if (subsection != null) {
+ config.append(" \"");
+ config.append(subsection);
+ config.append("\"");
+ }
+ config.append("]\n");
+ config.append(" ");
+ config.append(name);
+ config.append(" = ");
+ config.append(lfsUrl);
+ writeTrashFile(Constants.DOT_LFS_CONFIG, config.toString());
+ }
+
+ private void writeInvalidLfsConfig() throws IOException {
+ writeTrashFile(Constants.DOT_LFS_CONFIG,
+ "{lfs]\n url = " + LFS_SERVER_URL1);
+ }
+
+ private void checkLfsUrl(String lfsUrl) throws IOException {
+ HttpConnection lfsServerConn;
+ lfsServerConn = LfsConnectionFactory.getLfsConnection(db,
+ HttpSupport.METHOD_POST, Protocol.OPERATION_DOWNLOAD);
+
+ assertEquals(lfsUrl + Protocol.OBJECTS_LFS_ENDPOINT,
+ lfsServerConn.getURL().toString());
+ }
+}
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index fba58f8..09ffffb 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,31 +3,33 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs
Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.lfs;version="6.0.1",
- org.eclipse.jgit.lfs.errors;version="6.0.1",
- org.eclipse.jgit.lfs.internal;version="6.0.1";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
- org.eclipse.jgit.lfs.lib;version="6.0.1"
+Export-Package: org.eclipse.jgit.lfs;version="6.1.1",
+ org.eclipse.jgit.lfs.errors;version="6.1.1",
+ org.eclipse.jgit.lfs.internal;version="6.1.1";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
+ org.eclipse.jgit.lfs.lib;version="6.1.1"
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: com.google.gson;version="[2.8.2,3.0.0)",
com.google.gson.stream;version="[2.8.2,3.0.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)";resolution:=optional,
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.attributes;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.diff;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.hooks;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.pack;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.io;version="[6.0.1,6.1.0)"
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.attributes;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.diff;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.dircache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.hooks;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.pack;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
+ org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
index a715be6..7a2a446 100644
--- a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.lfs - Sources
Bundle-SymbolicName: org.eclipse.jgit.lfs.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index eb57db3..949c568 100644
--- a/org.eclipse.jgit.lfs/pom.xml
+++ b/org.eclipse.jgit.lfs/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs</artifactId>
diff --git a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
index 0e00f14..642b83d 100644
--- a/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
+++ b/org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties
@@ -1,19 +1,19 @@
corruptLongObject=The content hash ''{0}'' of the long object ''{1}'' doesn''t match its id, the corrupt object will be deleted.
-incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH.
-inconsistentMediafileLength=Mediafile {0} has unexpected length; expected {1} but found {2}.
+dotLfsConfigReadFailed=Reading .lfsconfig failed
inconsistentContentLength=Unexpected content length reported by LFS server ({0}), expected {1} but reported was {2}
+inconsistentMediafileLength=Mediafile {0} has unexpected length; expected {1} but found {2}.
+incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH.
invalidLongId=Invalid id: {0}
invalidLongIdLength=Invalid id length {0}; should be {1}
-lfsUnavailable=LFS is not available for repository {0}
-protocolError=LFS Protocol Error {0}: {1}
-requiredHashFunctionNotAvailable=Required hash function {0} not available.
-repositoryNotFound=Repository {0} not found
-repositoryReadOnly=Repository {0} is read-only
-lfsUnavailable=LFS is not available for repository {0}
-lfsUnathorized=Not authorized to perform operation {0} on repository {1}
lfsFailedToGetRepository=failed to get repository {0}
lfsNoDownloadUrl="Need to download object from LFS server but couldn't determine LFS server URL"
+lfsUnauthorized=Not authorized to perform operation {0} on repository {1}
+lfsUnavailable=LFS is not available for repository {0}
+missingLocalObject="Local Object {0} is missing"
+protocolError=LFS Protocol Error {0}: {1}
+repositoryNotFound=Repository {0} not found
+repositoryReadOnly=Repository {0} is read-only
+requiredHashFunctionNotAvailable=Required hash function {0} not available.
serverFailure=When trying to open a connection to {0} the server responded with an error code. rc={1}
-wrongAmoutOfDataReceived=While downloading data from the content server {0} {1} bytes have been received while {2} have been expected
userConfigInvalid="User config file {0} invalid {1}"
-missingLocalObject="Local Object {0} is missing"
\ No newline at end of file
+wrongAmountOfDataReceived=While downloading data from the content server {0} {1} bytes have been received while {2} have been expected
\ No newline at end of file
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
index d6ce855..ebf46e0 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java
@@ -113,6 +113,9 @@ private Set<LfsPointer> findObjectsToPush() throws IOException,
try (ObjectWalk walk = new ObjectWalk(getRepository())) {
for (RemoteRefUpdate up : refs) {
+ if (up.isDelete()) {
+ continue;
+ }
walk.setRewriteParents(false);
excludeRemoteRefs(walk);
walk.markStart(walk.parseCommit(up.getNewObjectId()));
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
index 3411887..c26a1bf 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
@@ -205,7 +205,7 @@ public static Collection<Path> downloadLfsResource(Lfs lfs, Repository db,
long bytesCopied = Files.copy(contentIn, path);
if (bytesCopied != o.size) {
throw new IOException(MessageFormat.format(
- LfsText.get().wrongAmoutOfDataReceived,
+ LfsText.get().wrongAmountOfDataReceived,
contentServerConn.getURL(),
Long.valueOf(bytesCopied),
Long.valueOf(o.size)));
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java
index 36889db..0dc6aea 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/errors/LfsUnauthorized.java
@@ -31,7 +31,7 @@ public class LfsUnauthorized extends LfsException {
* the repository name.
*/
public LfsUnauthorized(String operation, String name) {
- super(MessageFormat.format(LfsText.get().lfsUnathorized, operation,
+ super(MessageFormat.format(LfsText.get().lfsUnauthorized, operation,
name));
}
}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java
new file mode 100644
index 0000000..71d395c
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022, Matthias Fromme <mfromme@dspace.de>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lfs.internal;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException;
+import org.eclipse.jgit.lfs.lib.Constants;
+import org.eclipse.jgit.lib.BlobBasedConfig;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+import static org.eclipse.jgit.lib.Constants.HEAD;
+
+/**
+ * Encapsulate access to the .lfsconfig.
+ *
+ * According to the document
+ * https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-config.5.ronn
+ * the order to find the .lfsconfig file is:
+ *
+ * <pre>
+ * 1. in the root of the working tree
+ * 2. in the index
+ * 3. in the HEAD, for bare repositories this is the only place
+ * that is searched
+ * </pre>
+ *
+ * Values from the .lfsconfig are used only if not specified in another git
+ * config file to allow local override without modifiction of a committed file.
+ */
+public class LfsConfig {
+ private Repository db;
+ private Config delegate;
+
+ /**
+ * Create a new instance of the LfsConfig.
+ *
+ * @param db
+ * the associated repo
+ * @throws IOException
+ */
+ public LfsConfig(Repository db) throws IOException {
+ this.db = db;
+ delegate = this.load();
+ }
+
+ /**
+ * Read the .lfsconfig file from the repository
+ *
+ * @return The loaded lfs config or null if it does not exist
+ *
+ * @throws IOException
+ */
+ private Config load() throws IOException {
+ Config result = null;
+
+ if (!db.isBare()) {
+ result = loadFromWorkingTree();
+ if (result == null) {
+ result = loadFromIndex();
+ }
+ }
+
+ if (result == null) {
+ result = loadFromHead();
+ }
+
+ if (result == null) {
+ result = emptyConfig();
+ }
+
+ return result;
+ }
+
+ /**
+ * Try to read the lfs config from a file called .lfsconfig at the top level
+ * of the working tree.
+ *
+ * @return the config, or <code>null</code>
+ * @throws IOException
+ */
+ @Nullable
+ private Config loadFromWorkingTree()
+ throws IOException {
+ File lfsConfig = db.getFS().resolve(db.getWorkTree(),
+ Constants.DOT_LFS_CONFIG);
+ if (lfsConfig.exists() && lfsConfig.isFile()) {
+ FileBasedConfig config = new FileBasedConfig(lfsConfig, db.getFS());
+ try {
+ config.load();
+ return config;
+ } catch (ConfigInvalidException e) {
+ throw new LfsConfigInvalidException(
+ LfsText.get().dotLfsConfigReadFailed, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Try to read the lfs config from an entry called .lfsconfig contained in
+ * the index.
+ *
+ * @return the config, or <code>null</code> if the entry does not exist
+ * @throws IOException
+ */
+ @Nullable
+ private Config loadFromIndex()
+ throws IOException {
+ try {
+ DirCacheEntry entry = db.readDirCache()
+ .getEntry(Constants.DOT_LFS_CONFIG);
+ if (entry != null) {
+ return new BlobBasedConfig(null, db, entry.getObjectId());
+ }
+ } catch (ConfigInvalidException e) {
+ throw new LfsConfigInvalidException(
+ LfsText.get().dotLfsConfigReadFailed, e);
+ }
+ return null;
+ }
+
+ /**
+ * Try to read the lfs config from an entry called .lfsconfig contained in
+ * the head revision.
+ *
+ * @return the config, or <code>null</code> if the file does not exist
+ * @throws IOException
+ */
+ @Nullable
+ private Config loadFromHead() throws IOException {
+ try (RevWalk revWalk = new RevWalk(db)) {
+ ObjectId headCommitId = db.resolve(HEAD);
+ if (headCommitId == null) {
+ return null;
+ }
+ RevCommit commit = revWalk.parseCommit(headCommitId);
+ RevTree tree = commit.getTree();
+ TreeWalk treewalk = TreeWalk.forPath(db, Constants.DOT_LFS_CONFIG,
+ tree);
+ if (treewalk != null) {
+ return new BlobBasedConfig(null, db, treewalk.getObjectId(0));
+ }
+ } catch (ConfigInvalidException e) {
+ throw new LfsConfigInvalidException(
+ LfsText.get().dotLfsConfigReadFailed, e);
+ }
+ return null;
+ }
+
+ /**
+ * Create an empty config as fallback to avoid null pointer checks.
+ *
+ * @return an empty config
+ */
+ private Config emptyConfig() {
+ return new Config();
+ }
+
+ /**
+ * Get string value or null if not found.
+ *
+ * First tries to find the value in the git config files. If not found tries
+ * to find data in .lfsconfig.
+ *
+ * @param section
+ * the section
+ * @param subsection
+ * the subsection for the value
+ * @param name
+ * the key name
+ * @return a String value from the config, <code>null</code> if not found
+ */
+ public String getString(final String section, final String subsection,
+ final String name) {
+ String result = db.getConfig().getString(section, subsection, name);
+ if (result == null) {
+ result = delegate.getString(section, subsection, name);
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
index e221913..12b688d 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017, Markus Duft <markus.duft@ssi-schaefer.com> and others
+ * Copyright (C) 2017, 2022 Markus Duft <markus.duft@ssi-schaefer.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -39,12 +39,12 @@
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.util.HttpSupport;
import org.eclipse.jgit.util.SshSupport;
+import org.eclipse.jgit.util.StringUtils;
/**
* Provides means to get a valid LFS connection for a given repository.
*/
public class LfsConnectionFactory {
-
private static final int SSH_AUTH_TIMEOUT_SECONDS = 30;
private static final String SCHEME_HTTPS = "https"; //$NON-NLS-1$
private static final String SCHEME_SSH = "ssh"; //$NON-NLS-1$
@@ -64,7 +64,7 @@ public class LfsConnectionFactory {
* be used for
* @param purpose
* the action, e.g. Protocol.OPERATION_DOWNLOAD
- * @return the url for the lfs server. e.g.
+ * @return the connection for the lfs server. e.g.
* "https://github.com/github/git-lfs.git/info/lfs"
* @throws IOException
*/
@@ -92,13 +92,30 @@ public static HttpConnection getLfsConnection(Repository db, String method,
return connection;
}
+ /**
+ * Get LFS Server URL.
+ *
+ * @param db
+ * the repository to work with
+ * @param purpose
+ * the action, e.g. Protocol.OPERATION_DOWNLOAD
+ * @param additionalHeaders
+ * additional headers that can be used to connect to LFS server
+ * @return the URL for the LFS server. e.g.
+ * "https://github.com/github/git-lfs.git/info/lfs"
+ * @throws IOException
+ * if the LFS config is invalid or cannot be accessed
+ * @see <a href=
+ * "https://github.com/git-lfs/git-lfs/blob/main/docs/api/server-discovery.md">
+ * Server Discovery documentation</a>
+ */
private static String getLfsUrl(Repository db, String purpose,
Map<String, String> additionalHeaders)
- throws LfsConfigInvalidException {
- StoredConfig config = db.getConfig();
+ throws IOException {
+ LfsConfig config = new LfsConfig(db);
String lfsUrl = config.getString(ConfigConstants.CONFIG_SECTION_LFS,
- null,
- ConfigConstants.CONFIG_KEY_URL);
+ null, ConfigConstants.CONFIG_KEY_URL);
+
Exception ex = null;
if (lfsUrl == null) {
String remoteUrl = null;
@@ -106,6 +123,7 @@ private static String getLfsUrl(Repository db, String purpose,
lfsUrl = config.getString(ConfigConstants.CONFIG_SECTION_LFS,
remote,
ConfigConstants.CONFIG_KEY_URL);
+
// This could be done better (more precise logic), but according
// to https://github.com/git-lfs/git-lfs/issues/1759 git-lfs
// generally only supports 'origin' in an integrated workflow.
@@ -125,8 +143,6 @@ private static String getLfsUrl(Repository db, String purpose,
| CommandFailedException e) {
ex = e;
}
- } else {
- lfsUrl = lfsUrl + Protocol.INFO_LFS_ENDPOINT;
}
}
if (lfsUrl == null) {
@@ -149,7 +165,8 @@ private static String discoverLfsUrl(Repository db, String purpose,
additionalHeaders.putAll(action.header);
return action.href;
}
- return remoteUrl + Protocol.INFO_LFS_ENDPOINT;
+ return StringUtils.nameWithDotGit(remoteUrl)
+ + Protocol.INFO_LFS_ENDPOINT;
}
private static Protocol.ExpiringAction getSshAuthentication(
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
index 1ca37a9..06234c1 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java
@@ -28,21 +28,22 @@ public static LfsText get() {
// @formatter:off
/***/ public String corruptLongObject;
- /***/ public String inconsistentMediafileLength;
+ /***/ public String dotLfsConfigReadFailed;
/***/ public String inconsistentContentLength;
+ /***/ public String inconsistentMediafileLength;
/***/ public String incorrectLONG_OBJECT_ID_LENGTH;
/***/ public String invalidLongId;
/***/ public String invalidLongIdLength;
- /***/ public String lfsUnavailable;
- /***/ public String protocolError;
- /***/ public String requiredHashFunctionNotAvailable;
- /***/ public String repositoryNotFound;
- /***/ public String repositoryReadOnly;
- /***/ public String lfsUnathorized;
/***/ public String lfsFailedToGetRepository;
/***/ public String lfsNoDownloadUrl;
- /***/ public String serverFailure;
- /***/ public String wrongAmoutOfDataReceived;
- /***/ public String userConfigInvalid;
+ /***/ public String lfsUnauthorized;
+ /***/ public String lfsUnavailable;
/***/ public String missingLocalObject;
+ /***/ public String protocolError;
+ /***/ public String repositoryNotFound;
+ /***/ public String repositoryReadOnly;
+ /***/ public String requiredHashFunctionNotAvailable;
+ /***/ public String serverFailure;
+ /***/ public String userConfigInvalid;
+ /***/ public String wrongAmountOfDataReceived;
}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
index 3212a63..9b41ec3 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
@@ -82,6 +82,13 @@ public final class Constants {
public static final String ATTR_FILTER_DRIVER_PREFIX = "lfs/";
/**
+ * Config file name for lfs specific configuration
+ *
+ * @since 6.1
+ */
+ public static final String DOT_LFS_CONFIG = ".lfsconfig";
+
+ /**
* Create a new digest function for objects.
*
* @return a new digest object.
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 cc1bf85..cd22e24 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="6.0.1.qualifier"
+ version="6.1.1.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 874b274..54feb9d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
index be02662..2061948 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.gpg.bc"
label="%featureName"
- version="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import plugin="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
index 2909e80..760903e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 8937a83..e899ad5 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="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import plugin="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
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 2292c2e..b725dff 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
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 6eee7cd..99073e4 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="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -24,7 +24,7 @@
<requires>
<import plugin="com.jcraft.jsch"/>
- <import plugin="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
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 dc4159b..3566dbb 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
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 f0a4884..c04051b 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="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import feature="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
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 e344c19..50338a6 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
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 f5889e5..3939f51 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="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -35,9 +35,9 @@
version="0.0.0"/>
<requires>
- <import feature="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
- <import feature="org.eclipse.jgit.lfs" version="6.0.1" match="equivalent"/>
- <import feature="org.eclipse.jgit.ssh.apache" version="6.0.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit.lfs" version="6.1.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit.ssh.apache" version="6.1.1" 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 ae95704..4b0e26a 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
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 e12e599..9ccf39e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 d5d1554..d3e662b 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="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import feature="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
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 a20645e..d8b5de2 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
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
@@ -30,7 +30,7 @@
<dependency>
<groupId>org.eclipse.jgit.feature</groupId>
<artifactId>org.eclipse.jgit</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</dependency>
</dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
index ae62fa0..e039647 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.ssh.apache"
label="%featureName"
- version="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import feature="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
index 6f12afa..591b448 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
index df42e93..3df4a92 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.ssh.jsch"
label="%featureName"
- version="6.0.1.qualifier"
+ version="6.1.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import plugin="org.eclipse.jgit" version="6.0.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
</requires>
<plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
index 37ada5d..e461bff 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 d31cd37..5d61eef 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: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
index 91370cc..4e40232 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.17" sequenceNumber="1641393954">
+<target name="jgit-4.17" sequenceNumber="1646256653">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -23,8 +23,8 @@
<repository id="jetty-10.0.x" location="https://download.eclipse.org/eclipse/jetty/10.0.6/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="com.google.gson" version="2.8.8.v20211029-0838"/>
- <unit id="com.google.gson.source" version="2.8.8.v20211029-0838"/>
+ <unit id="com.google.gson" version="2.8.9.v20220111-1409"/>
+ <unit id="com.google.gson.source" version="2.8.9.v20220111-1409"/>
<unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -51,22 +51,22 @@
<unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
<unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
<unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.sshd.osgi" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.osgi.source" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp.source" version="2.7.0.v20210623-0618"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.sshd.osgi" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.8.0.v20211227-1750"/>
<unit id="org.assertj" version="3.20.2.v20210706-1104"/>
<unit id="org.assertj.source" version="3.20.2.v20210706-1104"/>
- <unit id="org.bouncycastle.bcpg" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcprov" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcprov.source" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcutil" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcutil.source" version="1.69.0.v20210713-1924"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil.source" version="1.70.0.v20220105-1522"/>
<unit id="org.hamcrest" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.source" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
@@ -87,7 +87,7 @@
<unit id="org.slf4j.binding.simple.source" version="1.7.30.v20200204-2150"/>
<unit id="org.tukaani.xz" version="1.9.0.v20210624-1259"/>
<unit id="org.tukaani.xz.source" version="1.9.0.v20210624-1259"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/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.17.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
index c2b13cc..dbb450a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
@@ -1,7 +1,7 @@
target "jgit-4.17" with source configurePhase
include "projects/jetty-10.0.x.tpd"
-include "orbit/R20211213173813-2021-12.tpd"
+include "orbit/R20220302172233-2022-03.tpd"
location "https://download.eclipse.org/releases/2020-09/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
index 28204f5..1628217 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.18" sequenceNumber="1641394122">
+<target name="jgit-4.18" sequenceNumber="1646256653">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -23,8 +23,8 @@
<repository id="jetty-10.0.x" location="https://download.eclipse.org/eclipse/jetty/10.0.6/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="com.google.gson" version="2.8.8.v20211029-0838"/>
- <unit id="com.google.gson.source" version="2.8.8.v20211029-0838"/>
+ <unit id="com.google.gson" version="2.8.9.v20220111-1409"/>
+ <unit id="com.google.gson.source" version="2.8.9.v20220111-1409"/>
<unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -51,22 +51,22 @@
<unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
<unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
<unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.sshd.osgi" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.osgi.source" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp.source" version="2.7.0.v20210623-0618"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.sshd.osgi" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.8.0.v20211227-1750"/>
<unit id="org.assertj" version="3.20.2.v20210706-1104"/>
<unit id="org.assertj.source" version="3.20.2.v20210706-1104"/>
- <unit id="org.bouncycastle.bcpg" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcprov" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcprov.source" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcutil" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcutil.source" version="1.69.0.v20210713-1924"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil.source" version="1.70.0.v20220105-1522"/>
<unit id="org.hamcrest" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.source" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
@@ -87,7 +87,7 @@
<unit id="org.slf4j.binding.simple.source" version="1.7.30.v20200204-2150"/>
<unit id="org.tukaani.xz" version="1.9.0.v20210624-1259"/>
<unit id="org.tukaani.xz.source" version="1.9.0.v20210624-1259"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/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.18.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
index ff6741d..911c67c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd
@@ -1,7 +1,7 @@
target "jgit-4.18" with source configurePhase
include "projects/jetty-10.0.x.tpd"
-include "orbit/R20211213173813-2021-12.tpd"
+include "orbit/R20220302172233-2022-03.tpd"
location "https://download.eclipse.org/releases/2020-12/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target
index 20b0529..ab18f7b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.19-staging" sequenceNumber="1641394141">
+<target name="jgit-4.19-staging" sequenceNumber="1646256653">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -23,8 +23,8 @@
<repository id="jetty-10.0.x" location="https://download.eclipse.org/eclipse/jetty/10.0.6/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="com.google.gson" version="2.8.8.v20211029-0838"/>
- <unit id="com.google.gson.source" version="2.8.8.v20211029-0838"/>
+ <unit id="com.google.gson" version="2.8.9.v20220111-1409"/>
+ <unit id="com.google.gson.source" version="2.8.9.v20220111-1409"/>
<unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -51,22 +51,22 @@
<unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
<unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
<unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.sshd.osgi" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.osgi.source" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp.source" version="2.7.0.v20210623-0618"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.sshd.osgi" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.8.0.v20211227-1750"/>
<unit id="org.assertj" version="3.20.2.v20210706-1104"/>
<unit id="org.assertj.source" version="3.20.2.v20210706-1104"/>
- <unit id="org.bouncycastle.bcpg" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcprov" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcprov.source" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcutil" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcutil.source" version="1.69.0.v20210713-1924"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil.source" version="1.70.0.v20220105-1522"/>
<unit id="org.hamcrest" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.source" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
@@ -87,7 +87,7 @@
<unit id="org.slf4j.binding.simple.source" version="1.7.30.v20200204-2150"/>
<unit id="org.tukaani.xz" version="1.9.0.v20210624-1259"/>
<unit id="org.tukaani.xz.source" version="1.9.0.v20210624-1259"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/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.19.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd
index 8fcaa47..fdb8b11 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd
@@ -1,7 +1,7 @@
target "jgit-4.19-staging" with source configurePhase
include "projects/jetty-10.0.x.tpd"
-include "orbit/R20211213173813-2021-12.tpd"
+include "orbit/R20220302172233-2022-03.tpd"
location "https://download.eclipse.org/staging/2021-03/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target
index 153314d..4c840dc 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.20" sequenceNumber="1641394152">
+<target name="jgit-4.20" sequenceNumber="1646256653">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -23,8 +23,8 @@
<repository id="jetty-10.0.x" location="https://download.eclipse.org/eclipse/jetty/10.0.6/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="com.google.gson" version="2.8.8.v20211029-0838"/>
- <unit id="com.google.gson.source" version="2.8.8.v20211029-0838"/>
+ <unit id="com.google.gson" version="2.8.9.v20220111-1409"/>
+ <unit id="com.google.gson.source" version="2.8.9.v20220111-1409"/>
<unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -51,22 +51,22 @@
<unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
<unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
<unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.sshd.osgi" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.osgi.source" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp.source" version="2.7.0.v20210623-0618"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.sshd.osgi" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.8.0.v20211227-1750"/>
<unit id="org.assertj" version="3.20.2.v20210706-1104"/>
<unit id="org.assertj.source" version="3.20.2.v20210706-1104"/>
- <unit id="org.bouncycastle.bcpg" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcprov" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcprov.source" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcutil" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcutil.source" version="1.69.0.v20210713-1924"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil.source" version="1.70.0.v20220105-1522"/>
<unit id="org.hamcrest" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.source" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
@@ -87,7 +87,7 @@
<unit id="org.slf4j.binding.simple.source" version="1.7.30.v20200204-2150"/>
<unit id="org.tukaani.xz" version="1.9.0.v20210624-1259"/>
<unit id="org.tukaani.xz.source" version="1.9.0.v20210624-1259"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/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.20.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd
index 33adb72..120ee64 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd
@@ -1,7 +1,7 @@
target "jgit-4.20" with source configurePhase
include "projects/jetty-10.0.x.tpd"
-include "orbit/R20211213173813-2021-12.tpd"
+include "orbit/R20220302172233-2022-03.tpd"
location "https://download.eclipse.org/releases/2021-06/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target
index 07de1af..7e8cd91 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.21" sequenceNumber="1641394170">
+<target name="jgit-4.21" sequenceNumber="1646256653">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -23,8 +23,8 @@
<repository id="jetty-10.0.x" location="https://download.eclipse.org/eclipse/jetty/10.0.6/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="com.google.gson" version="2.8.8.v20211029-0838"/>
- <unit id="com.google.gson.source" version="2.8.8.v20211029-0838"/>
+ <unit id="com.google.gson" version="2.8.9.v20220111-1409"/>
+ <unit id="com.google.gson.source" version="2.8.9.v20220111-1409"/>
<unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -51,22 +51,22 @@
<unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
<unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
<unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.sshd.osgi" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.osgi.source" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp.source" version="2.7.0.v20210623-0618"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.sshd.osgi" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.8.0.v20211227-1750"/>
<unit id="org.assertj" version="3.20.2.v20210706-1104"/>
<unit id="org.assertj.source" version="3.20.2.v20210706-1104"/>
- <unit id="org.bouncycastle.bcpg" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcprov" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcprov.source" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcutil" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcutil.source" version="1.69.0.v20210713-1924"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil.source" version="1.70.0.v20220105-1522"/>
<unit id="org.hamcrest" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.source" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
@@ -87,7 +87,7 @@
<unit id="org.slf4j.binding.simple.source" version="1.7.30.v20200204-2150"/>
<unit id="org.tukaani.xz" version="1.9.0.v20210624-1259"/>
<unit id="org.tukaani.xz.source" version="1.9.0.v20210624-1259"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/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.21.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd
index adf62d5..0ec2a52 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd
@@ -1,7 +1,7 @@
target "jgit-4.21" with source configurePhase
include "projects/jetty-10.0.x.tpd"
-include "orbit/R20211213173813-2021-12.tpd"
+include "orbit/R20220302172233-2022-03.tpd"
location "https://download.eclipse.org/releases/2021-09/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target
index 97b5fb6..b229da1 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.22" sequenceNumber="1641394177">
+<target name="jgit-4.22" sequenceNumber="1646256653">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -23,8 +23,8 @@
<repository id="jetty-10.0.x" location="https://download.eclipse.org/eclipse/jetty/10.0.6/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="com.google.gson" version="2.8.8.v20211029-0838"/>
- <unit id="com.google.gson.source" version="2.8.8.v20211029-0838"/>
+ <unit id="com.google.gson" version="2.8.9.v20220111-1409"/>
+ <unit id="com.google.gson.source" version="2.8.9.v20220111-1409"/>
<unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/>
<unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/>
@@ -51,22 +51,22 @@
<unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/>
<unit id="org.apache.httpcomponents.httpclient" version="4.5.13.v20210128-2225"/>
<unit id="org.apache.httpcomponents.httpclient.source" version="4.5.13.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.14.v20210128-2225"/>
- <unit id="org.apache.sshd.osgi" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.osgi.source" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp" version="2.7.0.v20210623-0618"/>
- <unit id="org.apache.sshd.sftp.source" version="2.7.0.v20210623-0618"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.15.v20220209-2345"/>
+ <unit id="org.apache.sshd.osgi" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp" version="2.8.0.v20211227-1750"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.8.0.v20211227-1750"/>
<unit id="org.assertj" version="3.20.2.v20210706-1104"/>
<unit id="org.assertj.source" version="3.20.2.v20210706-1104"/>
- <unit id="org.bouncycastle.bcpg" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcpkix.source" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcprov" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcprov.source" version="1.69.0.v20210923-1401"/>
- <unit id="org.bouncycastle.bcutil" version="1.69.0.v20210713-1924"/>
- <unit id="org.bouncycastle.bcutil.source" version="1.69.0.v20210713-1924"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcutil.source" version="1.70.0.v20220105-1522"/>
<unit id="org.hamcrest" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.source" version="2.2.0.v20210711-0821"/>
<unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/>
@@ -87,7 +87,7 @@
<unit id="org.slf4j.binding.simple.source" version="1.7.30.v20200204-2150"/>
<unit id="org.tukaani.xz" version="1.9.0.v20210624-1259"/>
<unit id="org.tukaani.xz.source" version="1.9.0.v20210624-1259"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/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.22.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd
index 37c93a7..eb1723c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd
@@ -1,7 +1,7 @@
target "jgit-4.22" with source configurePhase
include "projects/jetty-10.0.x.tpd"
-include "orbit/R20211213173813-2021-12.tpd"
+include "orbit/R20220302172233-2022-03.tpd"
location "https://download.eclipse.org/releases/2021-12/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220302172233-2022-03.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220302172233-2022-03.tpd
new file mode 100644
index 0000000..fafc689
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220302172233-2022-03.tpd
@@ -0,0 +1,69 @@
+target "R20220302172233" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/repository" {
+ com.google.gson [2.8.9.v20220111-1409,2.8.9.v20220111-1409]
+ com.google.gson.source [2.8.9.v20220111-1409,2.8.9.v20220111-1409]
+ com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+ com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+ com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+ com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
+ com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343]
+ com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343]
+ com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004]
+ com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004]
+ javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839]
+ javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839]
+ net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410]
+ net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534]
+ net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534]
+ net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410]
+ net.i2p.crypto.eddsa [0.3.0.v20210923-1401,0.3.0.v20210923-1401]
+ net.i2p.crypto.eddsa.source [0.3.0.v20210923-1401,0.3.0.v20210923-1401]
+ org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452]
+ org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452]
+ org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422]
+ org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422]
+ org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100]
+ org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100]
+ org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+ org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+ org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+ org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+ org.apache.httpcomponents.httpcore [4.4.15.v20220209-2345,4.4.15.v20220209-2345]
+ org.apache.httpcomponents.httpcore.source [4.4.15.v20220209-2345,4.4.15.v20220209-2345]
+ org.apache.sshd.osgi [2.8.0.v20211227-1750,2.8.0.v20211227-1750]
+ org.apache.sshd.osgi.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750]
+ org.apache.sshd.sftp [2.8.0.v20211227-1750,2.8.0.v20211227-1750]
+ org.apache.sshd.sftp.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750]
+ org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104]
+ org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104]
+ org.bouncycastle.bcpg [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcpg.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcpkix [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcpkix.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcprov [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcprov.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcutil [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.bouncycastle.bcutil.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522]
+ org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821]
+ org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821]
+ org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+ org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+ org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+ org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+ org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956]
+ org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956]
+ org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+ org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+ org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642]
+ org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642]
+ org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+ org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+ org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+ org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+ org.slf4j.binding.simple [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+ org.slf4j.binding.simple.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+ org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259]
+ org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259]
+}
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 8bee1fc..2a95042 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 80a64bd..b650598 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -16,7 +16,7 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 af00b0a..f5c4de4 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -3,28 +3,30 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.pgm.test
Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Import-Package: org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.diff;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.dircache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="6.0.1",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.merge;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.pgm;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.pgm.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.pgm.opt;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.io;version="[6.0.1,6.1.0)",
+Import-Package: org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.diff;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.dircache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="6.1.1",
+ org.eclipse.jgit.internal.storage.file;version="6.1.1",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.merge;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.pgm;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.pgm.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.pgm.opt;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
org.hamcrest.core;bundle-version="[2.2.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.rules;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index cd2bb63..c824788 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
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 4bad73b..c785443 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
@@ -89,6 +89,31 @@ public void testDescribeCommitMatch() throws Exception {
}
@Test
+ public void testDescribeCommitMatchAbbrev() throws Exception {
+ initialCommitAndTag();
+ secondCommit();
+ assertArrayEquals(new String[] { "v1.0-1-g56f6cebdf3f5", "" },
+ execute("git describe --abbrev 12 --match v1.*"));
+ }
+
+ @Test
+ public void testDescribeCommitMatchAbbrevMin() throws Exception {
+ initialCommitAndTag();
+ secondCommit();
+ assertArrayEquals(new String[] { "v1.0-1-g56f6", "" },
+ execute("git describe --abbrev -5 --match v1.*"));
+ }
+
+ @Test
+ public void testDescribeCommitMatchAbbrevMax() throws Exception {
+ initialCommitAndTag();
+ secondCommit();
+ assertArrayEquals(new String[] {
+ "v1.0-1-g56f6cebdf3f5ceeecd803365abf0996fb1fa006d", "" },
+ execute("git describe --abbrev 50 --match v1.*"));
+ }
+
+ @Test
public void testDescribeCommitMatch2() throws Exception {
initialCommitAndTag();
secondCommit();
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
new file mode 100644
index 0000000..e7bf484
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2021, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.pgm;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.internal.diffmergetool.CommandLineDiffTool;
+import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.eclipse.jgit.pgm.opt.CmdLineParser;
+import org.eclipse.jgit.pgm.opt.SubcommandHandler;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.junit.Before;
+import org.junit.Test;
+import org.kohsuke.args4j.Argument;
+
+/**
+ * Testing the {@code difftool} command.
+ */
+public class DiffToolTest extends CLIRepositoryTestCase {
+ public static class GitCliJGitWrapperParser {
+ @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
+ TextBuiltin subcommand;
+
+ @Argument(index = 1, metaVar = "metaVar_arg")
+ List<String> arguments = new ArrayList<>();
+ }
+
+ private String[] runAndCaptureUsingInitRaw(String... args)
+ throws Exception {
+ CLIGitCommand.Result result = new CLIGitCommand.Result();
+
+ GitCliJGitWrapperParser bean = new GitCliJGitWrapperParser();
+ CmdLineParser clp = new CmdLineParser(bean);
+ clp.parseArgument(args);
+
+ TextBuiltin cmd = bean.subcommand;
+ cmd.initRaw(db, null, null, result.out, result.err);
+ cmd.execute(bean.arguments.toArray(new String[bean.arguments.size()]));
+ if (cmd.getOutputWriter() != null) {
+ cmd.getOutputWriter().flush();
+ }
+ if (cmd.getErrorWriter() != null) {
+ cmd.getErrorWriter().flush();
+ }
+ return result.outLines().toArray(new String[0]);
+ }
+
+ private Git git;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+ git.commit().setMessage("initial commit").call();
+ }
+
+ @Test
+ public void testTool() throws Exception {
+ RevCommit commit = createUnstagedChanges();
+ List<DiffEntry> changes = getRepositoryChanges(commit);
+ String[] expectedOutput = getExpectedDiffToolOutput(changes);
+
+ String[] options = {
+ "--tool",
+ "-t",
+ };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput,
+ runAndCaptureUsingInitRaw("difftool", option,
+ "some_tool"));
+ }
+ }
+
+ @Test
+ public void testToolTrustExitCode() throws Exception {
+ RevCommit commit = createUnstagedChanges();
+ List<DiffEntry> changes = getRepositoryChanges(commit);
+ String[] expectedOutput = getExpectedDiffToolOutput(changes);
+
+ String[] options = { "--tool", "-t", };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw("difftool",
+ "--trust-exit-code", option, "some_tool"));
+ }
+ }
+
+ @Test
+ public void testToolNoGuiNoPromptNoTrustExitcode() throws Exception {
+ RevCommit commit = createUnstagedChanges();
+ List<DiffEntry> changes = getRepositoryChanges(commit);
+ String[] expectedOutput = getExpectedDiffToolOutput(changes);
+
+ String[] options = { "--tool", "-t", };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw("difftool",
+ "--no-gui", "--no-prompt", "--no-trust-exit-code",
+ option, "some_tool"));
+ }
+ }
+
+ @Test
+ public void testToolCached() throws Exception {
+ RevCommit commit = createStagedChanges();
+ List<DiffEntry> changes = getRepositoryChanges(commit);
+ String[] expectedOutput = getExpectedDiffToolOutput(changes);
+
+ String[] options = { "--cached", "--staged", };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw("difftool",
+ option, "--tool", "some_tool"));
+ }
+ }
+
+ @Test
+ public void testToolHelp() throws Exception {
+ CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
+ List<String> expectedOutput = new ArrayList<>();
+ expectedOutput.add("git difftool --tool=<tool> may be set to one of the following:");
+ for (CommandLineDiffTool defaultTool : defaultTools) {
+ String toolName = defaultTool.name();
+ expectedOutput.add(toolName);
+ }
+ String[] userDefinedToolsHelp = {
+ "user-defined:",
+ "The following tools are valid, but not currently available:",
+ "Some of the tools listed above only work in a windowed",
+ "environment. If run in a terminal-only session, they will fail.",
+ };
+ expectedOutput.addAll(Arrays.asList(userDefinedToolsHelp));
+
+ String option = "--tool-help";
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput.toArray(new String[0]), runAndCaptureUsingInitRaw("difftool", option));
+ }
+
+ private RevCommit createUnstagedChanges() throws Exception {
+ writeTrashFile("a", "Hello world a");
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ RevCommit commit = git.commit().setMessage("files a & b").call();
+ writeTrashFile("a", "New Hello world a");
+ writeTrashFile("b", "New Hello world b");
+ return commit;
+ }
+
+ private RevCommit createStagedChanges() throws Exception {
+ RevCommit commit = createUnstagedChanges();
+ git.add().addFilepattern(".").call();
+ return commit;
+ }
+
+ private List<DiffEntry> getRepositoryChanges(RevCommit commit)
+ throws Exception {
+ TreeWalk tw = new TreeWalk(db);
+ tw.addTree(commit.getTree());
+ FileTreeIterator modifiedTree = new FileTreeIterator(db);
+ tw.addTree(modifiedTree);
+ List<DiffEntry> changes = DiffEntry.scan(tw);
+ return changes;
+ }
+
+ private String[] getExpectedDiffToolOutput(List<DiffEntry> changes) {
+ String[] expectedToolOutput = new String[changes.size()];
+ for (int i = 0; i < changes.size(); ++i) {
+ DiffEntry change = changes.get(i);
+ String newPath = change.getNewPath();
+ String oldPath = change.getOldPath();
+ String newIdName = change.getNewId().name();
+ String oldIdName = change.getOldId().name();
+ String expectedLine = "M\t" + newPath + " (" + newIdName + ")"
+ + "\t" + oldPath + " (" + oldIdName + ")";
+ expectedToolOutput[i] = expectedLine;
+ }
+ return expectedToolOutput;
+ }
+
+ private static void assertArrayOfLinesEquals(String failMessage,
+ String[] expected, String[] actual) {
+ assertEquals(failMessage, toString(expected), toString(actual));
+ }
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java
index 564bd5f..1c6b783 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/FetchTest.java
@@ -33,6 +33,7 @@ public void setUp() throws Exception {
git.commit().setMessage("initial commit").call();
Repository remoteRepository = createWorkRepository();
+ addRepoToClose(remoteRepository);
remoteGit = new Git(remoteRepository);
// setup the first repository to fetch from the second repository
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index ffaafc1..ed980b5 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.pgm
Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -14,47 +14,49 @@
org.eclipse.jetty.servlet;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util;version="[10.0.0,11.0.0)",
org.eclipse.jetty.util.component;version="[10.0.0,11.0.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.archive;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.awtui;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.blame;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.diff;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.dircache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.gitrepo;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.io;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.pack;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.server;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.server.fs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs.server.s3;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.merge;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.notes;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revplot;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.pack;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http.apache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.resolver;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.ssh.jsch;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.sshd;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.io;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.archive;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.awtui;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.blame;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.diff;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.dircache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.gitrepo;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.io;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.server;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.merge;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.notes;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revplot;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.pack;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http.apache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.ssh.jsch;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.sshd;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
org.kohsuke.args4j;version="[2.33.0,3.0.0)",
org.kohsuke.args4j.spi;version="[2.33.0,3.0.0)"
-Export-Package: org.eclipse.jgit.console;version="6.0.1";
+Export-Package: org.eclipse.jgit.console;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="6.0.1";
+ org.eclipse.jgit.pgm;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util.io,
org.eclipse.jgit.awtui,
@@ -66,14 +68,14 @@
org.eclipse.jgit.treewalk,
org.eclipse.jgit.api,
javax.swing",
- org.eclipse.jgit.pgm.debug;version="6.0.1";
+ org.eclipse.jgit.pgm.debug;version="6.1.1";
uses:="org.eclipse.jgit.util.io,
org.eclipse.jgit.pgm,
org.eclipse.jetty.servlet",
- org.eclipse.jgit.pgm.internal;version="6.0.1";
+ org.eclipse.jgit.pgm.internal;version="6.1.1";
x-friends:="org.eclipse.jgit.pgm.test,
org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="6.0.1";
+ org.eclipse.jgit.pgm.opt;version="6.1.1";
uses:="org.kohsuke.args4j,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index 26269d7..0a5dd88 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: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index e645255..8c44764 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -12,6 +12,7 @@
org.eclipse.jgit.pgm.Daemon
org.eclipse.jgit.pgm.Describe
org.eclipse.jgit.pgm.Diff
+org.eclipse.jgit.pgm.DiffTool
org.eclipse.jgit.pgm.DiffTree
org.eclipse.jgit.pgm.Fetch
org.eclipse.jgit.pgm.Gc
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 05e0bcc..c189dc7 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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 9745003..fda0bf6 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
@@ -58,6 +58,9 @@
dateInfo=Date: {0}
deletedBranch=Deleted branch {0}
deletedRemoteBranch=Deleted remote branch {0}
+diffToolHelpSetToFollowing='git difftool --tool=<tool>' may be set to one of the following:\n{0}\n\tuser-defined:\n{1}\nThe following tools are valid, but not currently available:\n{2}\nSome of the tools listed above only work in a windowed\nenvironment. If run in a terminal-only session, they will fail.
+diffToolLaunch=Viewing ({0}/{1}): '{2}'\nLaunch '{3}' [Y/n]?
+diffToolDied=external diff died, stopping at {0}
doesNotExist={0} does not exist
dontOverwriteLocalChanges=error: Your local changes to the following file would be overwritten by merge:
everythingUpToDate=Everything up-to-date
@@ -145,6 +148,7 @@
metaVar_seconds=SECONDS
metaVar_service=SERVICE
metaVar_tagLocalUser=<GPG key ID>
+metaVar_tool=TOOL
metaVar_treeish=tree-ish
metaVar_uriish=uri-ish
metaVar_url=URL
@@ -225,6 +229,7 @@
unsupportedOperation=Unsupported operation: {0}
untrackedFiles=Untracked files:
updating=Updating {0}..{1}
+usage_Abbrev=Instead of using the default number of hexadecimal digits (which will vary according to the number of objects in the repository with a default of 7) of the abbreviated object name, use <n> digits, or as many digits as needed to form a unique object name. An <n> of 0 will suppress long format, only showing the closest tag.
usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time
usage_AlwaysFallback=Show uniquely abbreviated commit object as fallback
usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR.
@@ -249,6 +254,8 @@
usage_DisplayTheVersionOfJgit=Display the version of jgit
usage_Gc=Cleanup unnecessary files and optimize the local repository
usage_Glog=View commit history as a graph
+usage_DiffGuiTool=When git-difftool is invoked with the -g or --gui option the default diff tool will be read from the configured diff.guitool variable instead of diff.tool.
+usage_noGui=The --no-gui option can be used to override -g or --gui setting.
usage_IndexPack=Build pack index file for an existing packed archive
usage_LFSDirectory=Directory to store large objects
usage_LFSPort=Server http port
@@ -295,6 +302,7 @@
usage_Status=Show the working tree status
usage_StopTrackingAFile=Stop tracking a file
usage_TextHashFunctions=Scan repository to compute maximum number of collisions for hash functions
+usage_ToolForDiff=Use the diff tool specified by <tool>. Run git difftool --tool-help for the list of valid <tool> settings.\nIf a diff tool is not specified, git difftool will use the configuration variable diff.tool.
usage_UpdateRemoteRepositoryFromLocalRefs=Update remote repository from local refs
usage_UseAll=Use all refs found in refs/
usage_UseTags=Use any tag including lightweight tags
@@ -341,6 +349,7 @@
usage_date=date format, one of default, rfc, local, iso, short, raw (as defined by git-log(1) ), locale or localelocal (jgit extensions)
usage_detectRenames=detect renamed files
usage_diffAlgorithm=the diff algorithm to use. Currently supported are: 'myers', 'histogram'
+usage_DiffTool=git difftool is a Git command that allows you to compare and edit files between revisions using common diff tools.\ngit difftool is a frontend to git diff and accepts the same options and arguments.
usage_directoriesToExport=directories to export
usage_disableTheServiceInAllRepositories=disable the service in all repositories
usage_displayAListOfAllRegisteredJgitCommands=Display a list of all registered jgit commands
@@ -395,6 +404,8 @@
usage_performFsckStyleChecksOnReceive=perform fsck style checks on receive
usage_portNumberToListenOn=port number to listen on
usage_printOnlyBranchesThatContainTheCommit=print only branches that contain the commit
+usage_prompt=Prompt before each invocation of the diff tool. This is the default behaviour; the option is provided to override any configuration settings.
+usage_noPrompt=Do not prompt before launching a diff tool.
usage_pruneStaleTrackingRefs=prune stale tracking refs
usage_pushUrls=push URLs are manipulated
usage_quiet=don't show progress messages
@@ -422,6 +433,8 @@
usage_sshDriver=Selects the built-in ssh library to use, JSch or Apache MINA sshd.
usage_symbolicVersionForTheProject=Symbolic version for the project
usage_tags=fetch all tags
+usage_trustExitCode=git-difftool invokes a diff tool individually on each file. Errors reported by the diff tool are ignored by default. Use --trust-exit-code to make git-difftool exit when an invoked diff tool returns a non-zero exit code.\ngit-difftool will forward the exit code of the invoked tool when --trust-exit-code is used.
+usage_noTrustExitCode=This option can be used to override --trust-exit-code setting.
usage_notags=do not fetch tags
usage_tagAnnotated=create an annotated tag, unsigned unless -s or -u are given, or config tag.gpgSign is true
usage_tagDelete=delete tag
@@ -430,6 +443,7 @@
usage_tagSign=create a signed annotated tag
usage_tagNoSign=suppress signing the tag
usage_tagVerify=Verify the GPG signature
+usage_toolHelp=Print a list of diff tools that may be used with --tool.
usage_untrackedFilesMode=show untracked files
usage_updateRef=reference to update
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
index 2b49cf7..1a3a2f6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
@@ -15,6 +15,7 @@
import static java.lang.Integer.valueOf;
import static java.lang.Long.valueOf;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
import java.io.IOException;
@@ -116,7 +117,8 @@ protected void run() {
boolean autoAbbrev = abbrev == 0;
if (abbrev == 0) {
- abbrev = db.getConfig().getInt("core", "abbrev", 7); //$NON-NLS-1$ //$NON-NLS-2$
+ abbrev = db.getConfig().getInt("core", "abbrev", //$NON-NLS-1$ //$NON-NLS-2$
+ OBJECT_ID_ABBREV_STRING_LENGTH);
}
if (!showBlankBoundary) {
root = db.getConfig().getBoolean("blame", "blankboundary", false); //$NON-NLS-1$ //$NON-NLS-2$
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 8aa119a..116db03 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
@@ -44,6 +44,9 @@ class Describe extends TextBuiltin {
@Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern")
private List<String> patterns = new ArrayList<>();
+ @Option(name = "--abbrev", usage = "usage_Abbrev")
+ private Integer abbrev;
+
/** {@inheritDoc} */
@Override
protected void run() {
@@ -57,6 +60,9 @@ protected void run() {
cmd.setTags(useTags);
cmd.setAlways(always);
cmd.setMatch(patterns.toArray(new String[0]));
+ if (abbrev != null) {
+ cmd.setAbbrev(abbrev.intValue());
+ }
String result = null;
try {
result = cmd.call();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
new file mode 100644
index 0000000..1288817
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.pgm;
+
+import static org.eclipse.jgit.lib.Constants.HEAD;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.AmbiguousObjectException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
+import org.eclipse.jgit.internal.diffmergetool.DiffTools;
+import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.StringUtils;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+@Command(name = "difftool", common = true, usage = "usage_DiffTool")
+class DiffTool extends TextBuiltin {
+ private DiffFormatter diffFmt;
+
+ private DiffTools diffTools;
+
+ @Argument(index = 0, metaVar = "metaVar_treeish")
+ private AbstractTreeIterator oldTree;
+
+ @Argument(index = 1, metaVar = "metaVar_treeish")
+ private AbstractTreeIterator newTree;
+
+ @Option(name = "--tool", aliases = {
+ "-t" }, metaVar = "metaVar_tool", usage = "usage_ToolForDiff")
+ private String toolName;
+
+ @Option(name = "--cached", aliases = { "--staged" }, usage = "usage_cached")
+ private boolean cached;
+
+ private BooleanTriState prompt = BooleanTriState.UNSET;
+
+ @Option(name = "--prompt", usage = "usage_prompt")
+ void setPrompt(@SuppressWarnings("unused") boolean on) {
+ prompt = BooleanTriState.TRUE;
+ }
+
+ @Option(name = "--no-prompt", aliases = { "-y" }, usage = "usage_noPrompt")
+ void noPrompt(@SuppressWarnings("unused") boolean on) {
+ prompt = BooleanTriState.FALSE;
+ }
+
+ @Option(name = "--tool-help", usage = "usage_toolHelp")
+ private boolean toolHelp;
+
+ private BooleanTriState gui = BooleanTriState.UNSET;
+
+ @Option(name = "--gui", aliases = { "-g" }, usage = "usage_DiffGuiTool")
+ void setGui(@SuppressWarnings("unused") boolean on) {
+ gui = BooleanTriState.TRUE;
+ }
+
+ @Option(name = "--no-gui", usage = "usage_noGui")
+ void noGui(@SuppressWarnings("unused") boolean on) {
+ gui = BooleanTriState.FALSE;
+ }
+
+ private BooleanTriState trustExitCode = BooleanTriState.UNSET;
+
+ @Option(name = "--trust-exit-code", usage = "usage_trustExitCode")
+ void setTrustExitCode(@SuppressWarnings("unused") boolean on) {
+ trustExitCode = BooleanTriState.TRUE;
+ }
+
+ @Option(name = "--no-trust-exit-code", usage = "usage_noTrustExitCode")
+ void noTrustExitCode(@SuppressWarnings("unused") boolean on) {
+ trustExitCode = BooleanTriState.FALSE;
+ }
+
+ @Option(name = "--", metaVar = "metaVar_paths", handler = PathTreeFilterHandler.class)
+ private TreeFilter pathFilter = TreeFilter.ALL;
+
+ @Override
+ protected void init(Repository repository, String gitDir) {
+ super.init(repository, gitDir);
+ diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
+ diffTools = new DiffTools(repository);
+ }
+
+ @Override
+ protected void run() {
+ try {
+ if (toolHelp) {
+ showToolHelp();
+ } else {
+ boolean showPrompt = diffTools.isInteractive();
+ if (prompt != BooleanTriState.UNSET) {
+ showPrompt = prompt == BooleanTriState.TRUE;
+ }
+ String toolNamePrompt = toolName;
+ if (showPrompt) {
+ if (StringUtils.isEmptyOrNull(toolNamePrompt)) {
+ toolNamePrompt = diffTools.getDefaultToolName(gui);
+ }
+ }
+ // get the changed files
+ List<DiffEntry> files = getFiles();
+ if (files.size() > 0) {
+ compare(files, showPrompt, toolNamePrompt);
+ }
+ }
+ outw.flush();
+ } catch (RevisionSyntaxException | IOException e) {
+ throw die(e.getMessage(), e);
+ } finally {
+ diffFmt.close();
+ }
+ }
+
+ private void compare(List<DiffEntry> files, boolean showPrompt,
+ String toolNamePrompt) throws IOException {
+ for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) {
+ DiffEntry ent = files.get(fileIndex);
+ String mergedFilePath = ent.getNewPath();
+ if (mergedFilePath.equals(DiffEntry.DEV_NULL)) {
+ mergedFilePath = ent.getOldPath();
+ }
+ // check if user wants to launch compare
+ boolean launchCompare = true;
+ if (showPrompt) {
+ launchCompare = isLaunchCompare(fileIndex + 1, files.size(),
+ mergedFilePath, toolNamePrompt);
+ }
+ if (launchCompare) {
+ switch (ent.getChangeType()) {
+ case MODIFY:
+ outw.println("M\t" + ent.getNewPath() //$NON-NLS-1$
+ + " (" + ent.getNewId().name() + ")" //$NON-NLS-1$ //$NON-NLS-2$
+ + "\t" + ent.getOldPath() //$NON-NLS-1$
+ + " (" + ent.getOldId().name() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ int ret = diffTools.compare(ent.getNewPath(),
+ ent.getOldPath(), ent.getNewId().name(),
+ ent.getOldId().name(), toolName, prompt, gui,
+ trustExitCode);
+ if (ret != 0) {
+ throw die(MessageFormat.format(
+ CLIText.get().diffToolDied, mergedFilePath));
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ @SuppressWarnings("boxing")
+ private boolean isLaunchCompare(int fileIndex, int fileCount,
+ String fileName, String toolNamePrompt) throws IOException {
+ boolean launchCompare = true;
+ outw.println(MessageFormat.format(CLIText.get().diffToolLaunch,
+ fileIndex, fileCount, fileName, toolNamePrompt));
+ outw.flush();
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader(ins, StandardCharsets.UTF_8));
+ String line = null;
+ if ((line = br.readLine()) != null) {
+ if (!line.equalsIgnoreCase("Y")) { //$NON-NLS-1$
+ launchCompare = false;
+ }
+ }
+ return launchCompare;
+ }
+
+ private void showToolHelp() throws IOException {
+ StringBuilder availableToolNames = new StringBuilder();
+ for (String name : diffTools.getAvailableTools().keySet()) {
+ availableToolNames.append(String.format("\t\t%s\n", name)); //$NON-NLS-1$
+ }
+ StringBuilder notAvailableToolNames = new StringBuilder();
+ for (String name : diffTools.getNotAvailableTools().keySet()) {
+ notAvailableToolNames.append(String.format("\t\t%s\n", name)); //$NON-NLS-1$
+ }
+ StringBuilder userToolNames = new StringBuilder();
+ Map<String, ExternalDiffTool> userTools = diffTools
+ .getUserDefinedTools();
+ for (String name : userTools.keySet()) {
+ userToolNames.append(String.format("\t\t%s.cmd %s\n", //$NON-NLS-1$
+ name, userTools.get(name).getCommand()));
+ }
+ outw.println(MessageFormat.format(
+ CLIText.get().diffToolHelpSetToFollowing, availableToolNames,
+ userToolNames, notAvailableToolNames));
+ }
+
+ private List<DiffEntry> getFiles()
+ throws RevisionSyntaxException, AmbiguousObjectException,
+ IncorrectObjectTypeException, IOException {
+ diffFmt.setRepository(db);
+ if (cached) {
+ if (oldTree == null) {
+ ObjectId head = db.resolve(HEAD + "^{tree}"); //$NON-NLS-1$
+ if (head == null) {
+ die(MessageFormat.format(CLIText.get().notATree, HEAD));
+ }
+ CanonicalTreeParser p = new CanonicalTreeParser();
+ try (ObjectReader reader = db.newObjectReader()) {
+ p.reset(reader, head);
+ }
+ oldTree = p;
+ }
+ newTree = new DirCacheIterator(db.readDirCache());
+ } else if (oldTree == null) {
+ oldTree = new DirCacheIterator(db.readDirCache());
+ newTree = new FileTreeIterator(db);
+ } else if (newTree == null) {
+ newTree = new FileTreeIterator(db);
+ }
+
+ TextProgressMonitor pm = new TextProgressMonitor(errw);
+ pm.setDelayStart(2, TimeUnit.SECONDS);
+ diffFmt.setProgressMonitor(pm);
+ diffFmt.setPathFilter(pathFilter);
+
+ List<DiffEntry> files = diffFmt.scan(oldTree, newTree);
+ return files;
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index ca4877f..27a3d90 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -10,6 +10,8 @@
package org.eclipse.jgit.pgm;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Map;
@@ -144,8 +146,10 @@ protected void run() {
case FAST_FORWARD:
ObjectId oldHeadId = oldHead.getObjectId();
if (oldHeadId != null) {
- String oldId = oldHeadId.abbreviate(7).name();
- String newId = result.getNewHead().abbreviate(7).name();
+ String oldId = oldHeadId
+ .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name();
+ String newId = result.getNewHead()
+ .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name();
outw.println(MessageFormat.format(CLIText.get().updating,
oldId, newId));
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
index 030119e..c63532d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reflog.java
@@ -9,6 +9,8 @@
*/
package org.eclipse.jgit.pgm;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import java.io.IOException;
import java.util.Collection;
@@ -45,7 +47,8 @@ protected void run() {
private String toString(ReflogEntry entry, int i) {
final StringBuilder s = new StringBuilder();
- s.append(entry.getNewId().abbreviate(7).name());
+ s.append(entry.getNewId().abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH)
+ .name());
s.append(" "); //$NON-NLS-1$
s.append(ref == null ? Constants.HEAD : Repository.shortenRefName(ref));
s.append("@{" + i + "}:"); //$NON-NLS-1$ //$NON-NLS-2$
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 8e49a76..7fe5b0f 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
@@ -136,6 +136,9 @@ public static String fatalError(String message) {
/***/ public String dateInfo;
/***/ public String deletedBranch;
/***/ public String deletedRemoteBranch;
+ /***/ public String diffToolHelpSetToFollowing;
+ /***/ public String diffToolLaunch;
+ /***/ public String diffToolDied;
/***/ public String doesNotExist;
/***/ public String dontOverwriteLocalChanges;
/***/ public String everythingUpToDate;
diff --git a/org.eclipse.jgit.ssh.apache.agent/BUILD b/org.eclipse.jgit.ssh.apache.agent/BUILD
index 0c8cf83..f2e4d55 100644
--- a/org.eclipse.jgit.ssh.apache.agent/BUILD
+++ b/org.eclipse.jgit.ssh.apache.agent/BUILD
@@ -17,6 +17,6 @@
"//lib:slf4j-api",
"//lib:sshd-osgi",
"//org.eclipse.jgit:jgit",
- "//org.eclipse.jgit.ssh.apache:ssh-apache"
+ "//org.eclipse.jgit.ssh.apache:ssh-apache",
],
)
diff --git a/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF
index 3fd0f52..1a5746d 100644
--- a/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF
@@ -2,15 +2,15 @@
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent;singleton:=true
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
-Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[6.0.1,6.1.0)"
+Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[6.1.1,6.2.0)"
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: org.eclipse.jgit.ssh.apache.agent
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Import-Package: org.eclipse.jgit.transport.sshd;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)"
+Import-Package: org.eclipse.jgit.transport.sshd;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)"
Require-Bundle: com.sun.jna;bundle-version="[5.8.0,6.0.0)",
com.sun.jna.platform;bundle-version="[5.8.0,6.0.0)"
-Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="6.0.1";x-internal:=true
+Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="6.1.1";x-internal:=true
diff --git a/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF
index 808de53..d06e6b1 100644
--- a/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.ssh.apache.agent - Sources
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache.agent/README.md b/org.eclipse.jgit.ssh.apache.agent/README.md
new file mode 100644
index 0000000..6d62a2f
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.agent/README.md
@@ -0,0 +1,82 @@
+# JGit SSH agent transport support for Apache MINA sshd
+
+This bundle provides optional support for communicating with an SSH agent
+for SSH or SFTP authentication. It is an OSGi fragment for bundle
+[org.eclipse.jgit.ssh.apache](../org.eclipse.jgit.ssh.apache/README.md),
+and it provides transports for local communication with SSH agents.
+
+## Supported SSH agent transports
+
+### Linux, OS X, BSD
+
+On Linux, OS X, and BSD, the only transport mechanism supported is the usual
+communication via a Unix domain socket. This is the only protocol the OpenSSH
+SSH agent supports. A Unix domain socket appears as a special file in the file
+system; this file name is typically available in the environment variable
+`SSH_AUTH_SOCK`.
+
+The SSH config `IdentityAgent` can be set to this socket filename to specify
+exactly which Unix domain socket to use, or it can be set to `SSH_AUTH_SOCK`
+to use the value from that environment variable. If `IdentityAgent` is not set
+at all, JGit uses `SSH_AUTH_SOCK` by default. If the variable is not set, no
+SSH agent will be used. `IdentityAgent` can also be set to `none` to not use
+any SSH agent.
+
+### Windows
+
+On Windows, two different transports are supported:
+
+* A transport over a Windows named pipe. This is used by Win32-OpenSSH, and is available for Pageant since version 0.75.
+* A Pageant-specific legacy transport via shared memory; useful for Pageant and GPG's gpg-agent.
+
+Possible settings of `IdentityAgent` to select a particular transport are
+
+* `//./pipe/openssh-ssh-agent`: the Windows named pipe of Win32-OpenSSH.
+* `//./pageant`: the shared-memory mechanism of Pageant.
+* `none`: do not use any SSH agent.
+* `//./pipe/<any_valid_pipe_name>`: use a specific Windows named pipe.
+
+The default transport on Windows if `IdentityAgent` is not set at all is the
+Pageant shared-memory transport. Environment variable `SSH_AUTH_SOCK` needs
+not be set for Pageant, and _must not_ be set for Win32-OpenSSH.
+
+It is also possible to use a named pipe as transport for Pageant (as of
+version 0.75). Unfortunately, Pageant unnecessarily cryptographically
+obfuscates the pipe name, so it is not possible for JGit to determine it
+automatically. The pipe name is `pageant.<user name>.<sha256>`, for instance
+`pageant.myself.c5687736ba755a70b000955cb191698aed7db221c2b0710199eb1f5298922ab5`.
+A user can look up the name by starting Pageant and then running the
+command `dir \\.\pipe\\` in a command shell. Once the name is known, setting
+`IdentityAgent` to the pipe name as
+`//./pipe/pageant.myself.c5687736ba755a70b000955cb191698aed7db221c2b0710199eb1f5298922ab5`
+makes JGit use this Windows named pipe for communication with Pageant.
+
+(You can use forward slashes in the `~/.ssh/config` file. SSH config file
+parsing has its own rules about backslashes in config files; which are
+treated as escape characters in some contexts. With backslashes one would
+have to write, e.g., `\\\\.\pipe\openssh-ssh-agent`.)
+
+With these two transport mechanisms, Pageant and Win32-OpenSSH are supported.
+As for GPG: the gpg-agent can be configured to emulate ssh-agent (presumably
+via a WinSockets2 "Unix domain socket" on Windows) or to emulate Pageant
+(using the shared memory mechanism). Running gpg-agent with the
+`enable-ssh-support` option is
+[reported not to work on Windows](https://dev.gnupg.org/T3883), though. But
+the PuTTY emulation in gpg-agent (option `enable-putty-support`) _should_ work,
+so it should be possible to use gpg-agent instead of Pageant.
+
+Neither Pageant (as of version 0.76) nor Win32-OpenSSH (as of version 8.6)
+support the `confirm` or lifetime constraints for `AddKeysToAgent`. gpg-agent
+apparently does, even when communicating over the Pageant shared memory
+mechanism.
+
+The ssh-agent from git bash on Windows is currently not supported. It would
+need a connector handling Cygwin socket files and the Cygwin handshake over
+a TCP stream socket bound to the loopback interface. The Cygwin socket file
+_is_ exposed in the Windows file system at %TEMP%\ssh-XXXXXXXXXX\agent.<number>,
+but it does not have a fixed name (the X's and the number are variable and
+change each time ssh-agent is started).
+
+## Implementation
+
+The implementation of all transports uses JNA.
\ No newline at end of file
diff --git a/org.eclipse.jgit.ssh.apache.agent/pom.xml b/org.eclipse.jgit.ssh.apache.agent/pom.xml
index 1bd3fad..77b9c95 100644
--- a/org.eclipse.jgit.ssh.apache.agent/pom.xml
+++ b/org.eclipse.jgit.ssh.apache.agent/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.apache.agent</artifactId>
@@ -132,7 +132,6 @@
</configuration>
</plugin>
- <!-- New in 6.0; uncomment in 6.1
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
@@ -155,6 +154,9 @@
<includes>
<include>org.eclipse.jgit.*</include>
</includes>
+ <excludes>
+ <exclude>*.internal.*</exclude>
+ </excludes>
<accessModifier>public</accessModifier>
<breakBuildOnModifications>false</breakBuildOnModifications>
<breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
@@ -174,11 +176,9 @@
</execution>
</executions>
</plugin>
- -->
</plugins>
</build>
- <!-- New in 6.0, uncomment in 6.1
<reporting>
<plugins>
<plugin>
@@ -210,6 +210,9 @@
<includes>
<include>org.eclipse.jgit.*</include>
</includes>
+ <excludes>
+ <exclude>*.internal.*</exclude>
+ </excludes>
<accessModifier>public</accessModifier>
<breakBuildOnModifications>false</breakBuildOnModifications>
<breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
@@ -223,5 +226,4 @@
</plugin>
</plugins>
</reporting>
- -->
</project>
diff --git a/org.eclipse.jgit.ssh.apache.agent/resources/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.properties b/org.eclipse.jgit.ssh.apache.agent/resources/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.properties
index 6fce083..a3b4e91 100644
--- a/org.eclipse.jgit.ssh.apache.agent/resources/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.properties
+++ b/org.eclipse.jgit.ssh.apache.agent/resources/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.properties
@@ -2,9 +2,11 @@
errLastError=System message for error {0} could not be retrieved, got {1}
errReleaseSharedMemory=Cannot release shared memory: {0} - {1}
errUnknown=unknown error
+errUnknownIdentityAgent=IdentityAgent ''{0}'' unknown
logErrorLoadLibrary=Cannot load socket library; SSH agent support is switched off
msgCloseFailed=Cannot close SSH agent socket {0}
msgConnectFailed=Could not connect to SSH agent via socket ''{0}''
+msgConnectPipeFailed=Could not connect to SSH agent via pipe ''{0}''
msgNoMappedFile=Could not create file mapping: {0} - {1}
msgNoSharedMemory=Could not initialize shared memory: {0} - {1}
msgPageantUnavailable=Could not connect to Pageant
@@ -15,3 +17,4 @@
msgShortRead=Short read from SSH agent, expected {0} bytes, got {1} bytes; last read() returned {2}
pageant=Pageant
unixDefaultAgent=ssh-agent
+winOpenSsh=Win32 OpenSSH
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Factory.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Factory.java
index d7409b0..1cee1be 100644
--- a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Factory.java
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Factory.java
@@ -11,11 +11,15 @@
import java.io.File;
import java.io.IOException;
+import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
import org.eclipse.jgit.transport.sshd.agent.Connector;
import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory;
+import org.eclipse.jgit.util.StringUtils;
import org.eclipse.jgit.util.SystemReader;
/**
@@ -29,7 +33,20 @@ public class Factory implements ConnectorFactory {
public Connector create(String identityAgent, File homeDir)
throws IOException {
if (SystemReader.getInstance().isWindows()) {
- return new PageantConnector();
+ if (StringUtils.isEmptyOrNull(identityAgent)) {
+ // Default.
+ return new PageantConnector();
+ }
+ String winPath = identityAgent.replace('/', '\\');
+ if (PageantConnector.DESCRIPTOR.getIdentityAgent()
+ .equalsIgnoreCase(winPath)) {
+ return new PageantConnector();
+ }
+ if (winPath.toLowerCase(Locale.ROOT).startsWith("\\\\.\\pipe\\")) { //$NON-NLS-1$
+ return new WinPipeConnector(winPath);
+ }
+ throw new IOException(MessageFormat.format(
+ Texts.get().errUnknownIdentityAgent, identityAgent));
}
return new UnixDomainSocketConnector(identityAgent);
}
@@ -55,7 +72,11 @@ public String getName() {
*/
@Override
public Collection<ConnectorDescriptor> getSupportedConnectors() {
- return Collections.singleton(getDefaultConnector());
+ if (SystemReader.getInstance().isWindows()) {
+ return List.of(PageantConnector.DESCRIPTOR,
+ WinPipeConnector.DESCRIPTOR);
+ }
+ return Collections.singleton(UnixDomainSocketConnector.DESCRIPTOR);
}
@Override
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/LibraryHolder.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/LibraryHolder.java
index b09b55f..0a592d0 100644
--- a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/LibraryHolder.java
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/LibraryHolder.java
@@ -53,6 +53,10 @@ private LibraryHolder() {
kernel = Kernel32.INSTANCE;
}
+ String systemError() {
+ return systemError("[{0}] - {1}"); //$NON-NLS-1$
+ }
+
String systemError(String pattern) {
int lastError = kernel.GetLastError();
String msg;
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/PageantConnector.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/PageantConnector.java
index b0e3bce..19684ec 100644
--- a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/PageantConnector.java
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/PageantConnector.java
@@ -26,7 +26,10 @@ public class PageantConnector extends AbstractConnector {
@Override
public String getIdentityAgent() {
- return "pageant"; //$NON-NLS-1$
+ // This must be an absolute Windows path name to avoid that
+ // OpenSshConfigFile treats it as a relative path name. Use an UNC
+ // name on localhost, like for pipes.
+ return "\\\\.\\pageant"; //$NON-NLS-1$
}
@Override
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Sockets.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Sockets.java
index 3d95bdb..52cf5f2 100644
--- a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Sockets.java
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Sockets.java
@@ -24,11 +24,6 @@ private Sockets() {
}
/**
- * Default SSH agent socket environment variable name.
- */
- public static final String ENV_SSH_AUTH_SOCK = "SSH_AUTH_SOCK"; //$NON-NLS-1$
-
- /**
* Domain for Unix domain sockets.
*/
public static final int AF_UNIX = 1;
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.java
index fb45b30..f387c76 100644
--- a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.java
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/Texts.java
@@ -31,9 +31,11 @@ public static Texts get() {
/***/ public String errLastError;
/***/ public String errReleaseSharedMemory;
/***/ public String errUnknown;
+ /***/ public String errUnknownIdentityAgent;
/***/ public String logErrorLoadLibrary;
/***/ public String msgCloseFailed;
/***/ public String msgConnectFailed;
+ /***/ public String msgConnectPipeFailed;
/***/ public String msgNoMappedFile;
/***/ public String msgNoSharedMemory;
/***/ public String msgPageantUnavailable;
@@ -44,5 +46,6 @@ public static Texts get() {
/***/ public String msgShortRead;
/***/ public String pageant;
/***/ public String unixDefaultAgent;
+ /***/ public String winOpenSsh;
}
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/UnixDomainSocketConnector.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/UnixDomainSocketConnector.java
index 3b75f3a..95ac34f 100644
--- a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/UnixDomainSocketConnector.java
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/UnixDomainSocketConnector.java
@@ -11,10 +11,10 @@
import static org.eclipse.jgit.internal.transport.sshd.agent.connector.Sockets.AF_UNIX;
import static org.eclipse.jgit.internal.transport.sshd.agent.connector.Sockets.DEFAULT_PROTOCOL;
-import static org.eclipse.jgit.internal.transport.sshd.agent.connector.Sockets.ENV_SSH_AUTH_SOCK;
import static org.eclipse.jgit.internal.transport.sshd.agent.connector.Sockets.SOCK_STREAM;
import static org.eclipse.jgit.internal.transport.sshd.agent.connector.UnixSockets.FD_CLOEXEC;
import static org.eclipse.jgit.internal.transport.sshd.agent.connector.UnixSockets.F_SETFD;
+import static org.eclipse.jgit.transport.SshConstants.ENV_SSH_AUTH_SOCKET;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -46,7 +46,7 @@ public class UnixDomainSocketConnector extends AbstractConnector {
@Override
public String getIdentityAgent() {
- return ENV_SSH_AUTH_SOCK;
+ return ENV_SSH_AUTH_SOCKET;
}
@Override
@@ -91,8 +91,9 @@ private static synchronized UnixSockets getLibrary() {
public UnixDomainSocketConnector(String socketFile) {
super();
String file = socketFile;
- if (StringUtils.isEmptyOrNull(file)) {
- file = SystemReader.getInstance().getenv(ENV_SSH_AUTH_SOCK);
+ if (StringUtils.isEmptyOrNull(file)
+ || ENV_SSH_AUTH_SOCKET.equals(file)) {
+ file = SystemReader.getInstance().getenv(ENV_SSH_AUTH_SOCKET);
}
this.socketFile = file;
}
diff --git a/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/WinPipeConnector.java b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/WinPipeConnector.java
new file mode 100644
index 0000000..7bad90f
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/WinPipeConnector.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.transport.sshd.agent.connector;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.common.SshException;
+import org.eclipse.jgit.transport.sshd.agent.AbstractConnector;
+import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory.ConnectorDescriptor;
+import org.eclipse.jgit.util.StringUtils;
+
+import com.sun.jna.LastErrorException;
+import com.sun.jna.platform.win32.WinBase;
+import com.sun.jna.platform.win32.WinError;
+import com.sun.jna.platform.win32.WinNT;
+import com.sun.jna.platform.win32.WinNT.HANDLE;
+import com.sun.jna.ptr.IntByReference;
+
+/**
+ * A connector based on JNA using Windows' named pipes to communicate with an
+ * ssh agent. This is used by Microsoft's Win32-OpenSSH port.
+ */
+public class WinPipeConnector extends AbstractConnector {
+
+ // Pipe names are, like other file names, case-insensitive on Windows.
+ private static final String CANONICAL_PIPE_NAME = "\\\\.\\pipe\\openssh-ssh-agent"; //$NON-NLS-1$
+
+ /**
+ * {@link ConnectorDescriptor} for the {@link PageantConnector}.
+ */
+ public static final ConnectorDescriptor DESCRIPTOR = new ConnectorDescriptor() {
+
+ @Override
+ public String getIdentityAgent() {
+ return CANONICAL_PIPE_NAME;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return Texts.get().winOpenSsh;
+ }
+ };
+
+ private static final int FILE_SHARE_NONE = 0;
+
+ private static final int FILE_ATTRIBUTE_NONE = 0;
+
+ private final String pipeName;
+
+ private final AtomicBoolean connected = new AtomicBoolean();
+
+ // It's a byte pipe, so the normal Windows file mechanisms can be used.
+ // Would one of the standard Java File I/O abstractions work?
+ private volatile HANDLE fileHandle;
+
+ /**
+ * Creates a {@link WinPipeConnector} for the given named pipe.
+ *
+ * @param pipeName
+ * to connect to
+ */
+ public WinPipeConnector(String pipeName) {
+ this.pipeName = pipeName.replace('/', '\\');
+ }
+
+ @Override
+ public boolean connect() throws IOException {
+ if (StringUtils.isEmptyOrNull(pipeName)) {
+ return false;
+ }
+ HANDLE file = fileHandle;
+ synchronized (this) {
+ if (connected.get()) {
+ return true;
+ }
+ LibraryHolder libs = LibraryHolder.getLibrary();
+ if (libs == null) {
+ return false;
+ }
+ file = libs.kernel.CreateFile(pipeName,
+ WinNT.GENERIC_READ | WinNT.GENERIC_WRITE, FILE_SHARE_NONE,
+ null, WinNT.OPEN_EXISTING, FILE_ATTRIBUTE_NONE, null);
+ if (file == null || file == WinBase.INVALID_HANDLE_VALUE) {
+ int errorCode = libs.kernel.GetLastError();
+ if (errorCode == WinError.ERROR_FILE_NOT_FOUND
+ && CANONICAL_PIPE_NAME.equalsIgnoreCase(pipeName)) {
+ // OpenSSH agent not running. Don't throw.
+ return false;
+ }
+ LastErrorException cause = new LastErrorException(
+ libs.systemError());
+ throw new IOException(MessageFormat
+ .format(Texts.get().msgConnectPipeFailed, pipeName),
+ cause);
+ }
+ connected.set(true);
+ }
+ fileHandle = file;
+ return connected.get();
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ HANDLE file = fileHandle;
+ if (connected.getAndSet(false) && fileHandle != null) {
+ fileHandle = null;
+ LibraryHolder libs = LibraryHolder.getLibrary();
+ boolean success = libs.kernel.CloseHandle(file);
+ if (!success) {
+ LastErrorException cause = new LastErrorException(
+ libs.systemError());
+ throw new IOException(MessageFormat
+ .format(Texts.get().msgCloseFailed, pipeName), cause);
+ }
+ }
+ }
+
+ @Override
+ public byte[] rpc(byte command, byte[] message) throws IOException {
+ prepareMessage(command, message);
+ HANDLE file = fileHandle;
+ if (!connected.get() || file == null) {
+ // No translation, internal error
+ throw new IllegalStateException("Not connected to SSH agent"); //$NON-NLS-1$
+ }
+ LibraryHolder libs = LibraryHolder.getLibrary();
+ writeFully(libs, file, message);
+ // Now receive the reply
+ byte[] lengthBuf = new byte[4];
+ readFully(libs, file, lengthBuf);
+ int length = toLength(command, lengthBuf);
+ byte[] payload = new byte[length];
+ readFully(libs, file, payload);
+ return payload;
+ }
+
+ private void writeFully(LibraryHolder libs, HANDLE file, byte[] message)
+ throws IOException {
+ byte[] buf = message;
+ int toWrite = buf.length;
+ try {
+ while (toWrite > 0) {
+ IntByReference written = new IntByReference();
+ boolean success = libs.kernel.WriteFile(file, buf, buf.length,
+ written, null);
+ if (!success) {
+ throw new LastErrorException(libs.systemError());
+ }
+ int actuallyWritten = written.getValue();
+ toWrite -= actuallyWritten;
+ if (actuallyWritten > 0 && toWrite > 0) {
+ buf = Arrays.copyOfRange(buf, actuallyWritten, buf.length);
+ }
+ }
+ } catch (LastErrorException e) {
+ throw new IOException(MessageFormat.format(
+ Texts.get().msgSendFailed, Integer.toString(message.length),
+ Integer.toString(toWrite)), e);
+ }
+ }
+
+ private void readFully(LibraryHolder libs, HANDLE file, byte[] data)
+ throws IOException {
+ int n = 0;
+ int offset = 0;
+ while (offset < data.length && (n = read(libs, file, data, offset,
+ data.length - offset)) > 0) {
+ offset += n;
+ }
+ if (offset < data.length) {
+ throw new SshException(MessageFormat.format(
+ Texts.get().msgShortRead, Integer.toString(data.length),
+ Integer.toString(offset), Integer.toString(n)));
+ }
+ }
+
+ private int read(LibraryHolder libs, HANDLE file, byte[] buffer, int offset,
+ int length) throws IOException {
+ try {
+ int toRead = length;
+ IntByReference read = new IntByReference();
+ if (offset == 0) {
+ boolean success = libs.kernel.ReadFile(file, buffer, toRead,
+ read, null);
+ if (!success) {
+ throw new LastErrorException(libs.systemError());
+ }
+ return read.getValue();
+ }
+ byte[] data = new byte[length];
+ boolean success = libs.kernel.ReadFile(file, buffer, toRead, read,
+ null);
+ if (!success) {
+ throw new LastErrorException(libs.systemError());
+ }
+ int actuallyRead = read.getValue();
+ if (actuallyRead > 0) {
+ System.arraycopy(data, 0, buffer, offset, actuallyRead);
+ }
+ return actuallyRead;
+ } catch (LastErrorException e) {
+ throw new IOException(MessageFormat.format(
+ Texts.get().msgReadFailed, Integer.toString(length)), e);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
index 8ff9735..411d43c 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -3,34 +3,34 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Import-Package: org.apache.sshd.client.config.hosts;version="[2.7.0,2.8.0)",
- org.apache.sshd.common;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.auth;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.config.keys;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.helpers;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.kex;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.keyprovider;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.session;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.signature;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.net;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.security;version="[2.7.0,2.8.0)",
- org.apache.sshd.core;version="[2.7.0,2.8.0)",
- org.apache.sshd.server;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.forward;version="[2.7.0,2.8.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.sshd.proxy;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit.ssh;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.sshd;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.sshd.agent;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+Import-Package: org.apache.sshd.client.config.hosts;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.auth;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.config.keys;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.helpers;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.kex;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.keyprovider;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.session;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.signature;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.net;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.security;version="[2.8.0,2.9.0)",
+ org.apache.sshd.core;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.forward;version="[2.8.0,2.9.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit.ssh;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.sshd;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.sshd.agent;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.hamcrest;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.experimental.theories;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml
index a88ddaf..3e98e33 100644
--- a/org.eclipse.jgit.ssh.apache.test/pom.xml
+++ b/org.eclipse.jgit.ssh.apache.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
index ccaf98c..3d7c765 100644
--- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
@@ -107,6 +107,32 @@ public void testEd25519HostKey() throws Exception {
"IdentityFile " + privateKey1.getAbsolutePath());
}
+ /**
+ * Test for SSHD-1231. If authentication is attempted first with an RSA key,
+ * which is rejected, and then with some other key type (here ed25519),
+ * authentication fails in bug SSHD-1231.
+ *
+ * @throws Exception
+ * on errors
+ * @see <a href=
+ * "https://issues.apache.org/jira/browse/SSHD-1231">SSHD-1231</a>
+ */
+ @Test
+ public void testWrongKeyFirst() throws Exception {
+ File userKey = new File(getTemporaryDirectory(), "userkey");
+ copyTestResource("id_ed25519", userKey);
+ File publicKey = new File(getTemporaryDirectory(), "userkey.pub");
+ copyTestResource("id_ed25519.pub", publicKey);
+ server.setTestUserPublicKey(publicKey.toPath());
+ cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, //
+ "Host git", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), // RSA
+ "IdentityFile " + userKey.getAbsolutePath());
+ }
+
@Test
public void testHashedKnownHosts() throws Exception {
assertTrue("Failed to delete known_hosts", knownHosts.delete());
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 81e01cc..73feaec 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -6,9 +6,9 @@
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Export-Package: org.eclipse.jgit.internal.transport.sshd;version="6.0.1";x-internal:=true;
+Export-Package: org.eclipse.jgit.internal.transport.sshd;version="6.1.1";x-internal:=true;
uses:="org.apache.sshd.client,
org.apache.sshd.client.auth,
org.apache.sshd.client.auth.keyboard,
@@ -23,72 +23,75 @@
org.apache.sshd.common.signature,
org.apache.sshd.common.util.buffer,
org.eclipse.jgit.transport",
- org.eclipse.jgit.internal.transport.sshd.agent;version="6.0.1";x-internal:=true,
- org.eclipse.jgit.internal.transport.sshd.auth;version="6.0.1";x-internal:=true,
- org.eclipse.jgit.internal.transport.sshd.proxy;version="6.0.1";x-friends:="org.eclipse.jgit.ssh.apache.test",
- org.eclipse.jgit.transport.sshd;version="6.0.1";
+ org.eclipse.jgit.internal.transport.sshd.agent;version="6.1.1";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.auth;version="6.1.1";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="6.1.1";x-friends:="org.eclipse.jgit.ssh.apache.test",
+ org.eclipse.jgit.transport.sshd;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.apache.sshd.client.config.hosts,
org.apache.sshd.common.keyprovider,
org.eclipse.jgit.util,
org.apache.sshd.client.session,
org.apache.sshd.client.keyverifier",
- org.eclipse.jgit.transport.sshd.agent;version="6.0.1"
+ org.eclipse.jgit.transport.sshd.agent;version="6.1.1"
Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)",
- org.apache.sshd.agent;version="[2.7.0,2.8.0)",
- org.apache.sshd.client;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.auth;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.auth.keyboard;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.auth.password;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.auth.pubkey;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.channel;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.config.hosts;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.config.keys;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.future;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.keyverifier;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.session;version="[2.7.0,2.8.0)",
- org.apache.sshd.client.session.forward;version="[2.7.0,2.8.0)",
- org.apache.sshd.common;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.auth;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.channel;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.compression;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.config.keys;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.config.keys.loader;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.digest;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.forward;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.future;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.helpers;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.io;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.kex;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.kex.extension;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.kex.extension.parser;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.keyprovider;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.mac;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.random;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.session;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.session.helpers;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.signature;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.buffer;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.closeable;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.io;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.io.functors;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.io.resource;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.logging;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.net;version="[2.7.0,2.8.0)",
- org.apache.sshd.common.util.security;version="[2.7.0,2.8.0)",
- org.apache.sshd.core;version="[2.7.0,2.8.0)",
- org.apache.sshd.server.auth;version="[2.7.0,2.8.0)",
- org.apache.sshd.sftp;version="[2.7.0,2.8.0)",
- org.apache.sshd.sftp.client;version="[2.7.0,2.8.0)",
- org.apache.sshd.sftp.common;version="[2.7.0,2.8.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.fnmatch;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.ssh;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.apache.sshd.agent;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.auth;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.auth.keyboard;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.auth.password;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.auth.pubkey;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.channel;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.config.hosts;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.config.keys;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.future;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.keyverifier;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.session;version="[2.8.0,2.9.0)",
+ org.apache.sshd.client.session.forward;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.auth;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.channel;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.compression;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.config.keys;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.config.keys.loader;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.config.keys.u2f;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.digest;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.forward;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.future;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.helpers;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.io;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.kex;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.kex.extension;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.kex.extension.parser;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.keyprovider;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.mac;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.random;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.session;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.session.helpers;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.signature;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.buffer;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.buffer.keys;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.closeable;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.io;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.io.der;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.io.functors;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.io.resource;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.logging;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.net;version="[2.8.0,2.9.0)",
+ org.apache.sshd.common.util.security;version="[2.8.0,2.9.0)",
+ org.apache.sshd.core;version="[2.8.0,2.9.0)",
+ org.apache.sshd.server.auth;version="[2.8.0,2.9.0)",
+ org.apache.sshd.sftp;version="[2.8.0,2.9.0)",
+ org.apache.sshd.sftp.client;version="[2.8.0,2.9.0)",
+ org.apache.sshd.sftp.common;version="[2.8.0,2.9.0)",
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.fnmatch;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
index b770b90..9fefa6e 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.ssh.apache - Sources
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache/README.md b/org.eclipse.jgit.ssh.apache/README.md
index cba87ac..f06b2f6 100644
--- a/org.eclipse.jgit.ssh.apache/README.md
+++ b/org.eclipse.jgit.ssh.apache/README.md
@@ -43,6 +43,53 @@
.call();
```
+## Support for SSH agents
+
+There exist two IETF draft RFCs for communication with an SSH agent:
+
+* an older [SSH1 protocol](https://tools.ietf.org/html/draft-ietf-secsh-agent-02) that can deal only with DSA and RSA keys, and
+* a newer [SSH2 protocol](https://tools.ietf.org/html/draft-miller-ssh-agent-04) (from OpenSSH).
+
+JGit only supports the newer OpenSSH protocol.
+
+Communication with an SSH agent can occur over any transport protocol, and different
+SSH agents may use different transports for local communication. JGit provides some
+transports via the [org.eclipse.jgit.ssh.apache.agent](../org.eclipse.jgit.ssh.apache.agent/README.md)
+fragment, which are discovered from `org.eclipse.jgit.ssh.apache` also via the `ServiceLoader` mechanism;
+the SPI (service provider interface) is `org.eclipse.jgit.transport.sshd.agent.ConnectorFactory`.
+
+If such a `ConnectorFactory` implementation is found, JGit may use an SSH agent. If none
+is available, JGit cannot communicate with an SSH agent, and will not attempt to use one.
+
+### SSH configurations for SSH agents
+
+There are several SSH properties that can be used in the `~/.ssh/config` file to configure
+the use of an SSH agent. For the details, see the [OpenBSD ssh-config documentation](https://man.openbsd.org/ssh_config.5).
+
+* **AddKeysToAgent** can be set to `no`, `yes`, or `ask`. If set to `yes`, keys will be added
+ to the agent if they're not yet in the agent. If set to `ask`, the user will be prompted
+ before doing so, and can opt out of adding the key. JGit also supports the additional
+ settings `confirm` and key lifetimes.
+* **IdentityAgent** can be set to choose which SSH agent to use, if there are several running.
+ It can also be set to `none` to explicitly switch off using an SSH agent at all.
+* **IdentitiesOnly** if set to `yes` and an SSH agent is used, only keys from the agent that are
+ also listed in an `IdentityFile` property will be considered. (It'll also switch off trying
+ default key names, such as `~/.ssh/id_rsa` or `~/.ssh/id_ed25519`; only keys listed explicitly
+ will be used.)
+
+### Limitations
+
+As mentioned above JGit only implements the newer OpenSSH protocol. OpenSSH fully implements this,
+but some other SSH agents only offer partial implementations. In particular on Windows, neither
+Pageant nor Win32-OpenSSH implement the `confirm` or lifetime constraints for `AddKeysToAgent`. With
+such SSH agents, these settings should not be used in `~/.ssh/config`. GPG's gpg-agent can be run
+with option `enable_putty_support` and can then be used as a Pageant replacement. gpg-agent appears
+to support these key constraints.
+
+OpenSSH does not implement ed448 keys, and neither does Apache MINA sshd, and hence such keys are
+not supported in JGit if its built-in SSH implementation is used. ed448 or other unsupported keys
+provided by an SSH agent are ignored.
+
## Using a different SSH implementation
To use a different SSH implementation:
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
index 340cca1..674c7a4 100644
--- a/org.eclipse.jgit.ssh.apache/pom.xml
+++ b/org.eclipse.jgit.ssh.apache/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
@@ -50,6 +50,16 @@
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-sftp</artifactId>
<version>${apache-sshd-version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-common</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
@@ -154,6 +164,9 @@
<includes>
<include>org.eclipse.jgit.*</include>
</includes>
+ <excludes>
+ <exclude>*.internal.*</exclude>
+ </excludes>
<accessModifier>public</accessModifier>
<breakBuildOnModifications>false</breakBuildOnModifications>
<breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
@@ -207,6 +220,9 @@
<includes>
<include>org.eclipse.jgit.*</include>
</includes>
+ <excludes>
+ <exclude>*.internal.*</exclude>
+ </excludes>
<accessModifier>public</accessModifier>
<breakBuildOnModifications>false</breakBuildOnModifications>
<breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
index 2bba736..4f735ba 100644
--- a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
+++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
@@ -1,5 +1,6 @@
authenticationCanceled=SSH authentication canceled: no password given
authenticationOnClosedSession=Authentication canceled: session is already closing or closed
+cannotReadPublicKey=Cannot read public key from file {0}
closeListenerFailed=Ssh session close listener failed
configInvalidPath=Invalid path in ssh config key {0}: {1}
configInvalidPattern=Invalid pattern in ssh config key {0}: {1}
@@ -77,6 +78,8 @@
proxySocksUnexpectedMessage=Unexpected message received from SOCKS5 proxy {0}; client state {1}: {2}
proxySocksUnexpectedVersion=Expected SOCKS version 5, got {0}
proxySocksUsernameTooLong=User name for proxy {0} must be at most 255 bytes long, is {1} bytes: {2}
+pubkeyAuthAddKeyToAgentError=Could not add {0} key with fingerprint {1} to the SSH agent
+pubkeyAuthAddKeyToAgentQuestion=Add the {0} key with fingerprint {1} to the SSH agent?
pubkeyAuthWrongCommand=Public key authentication received unknown SSH command {0} from {1} ({2})
pubkeyAuthWrongKey=Public key authentication received wrong key; sent {0}, got back {1} from {2} ({3})
pubkeyAuthWrongSignatureAlgorithm=Public key authentication requested signature type {0} but got back {1} from {2} ({3})
@@ -85,9 +88,13 @@
serverIdWithNul=Server identification contains a NUL character: {0}
sessionCloseFailed=Closing the session failed
sessionWithoutUsername=SSH session created without user name; cannot authenticate
+sshAgentEdDSAFormatError=Cannot add ed25519 key to the SSH agent because it is encoded as {0} instead of PKCS#8
+sshAgentPayloadLengthError=Expected {0,choice,0#no bytes|1#one byte|1<{0} bytes} but got {1}
sshAgentReplyLengthError=Invalid SSH agent reply message length {0} after command {1}
sshAgentReplyUnexpected=Unexpected reply from ssh-agent: {0}
sshAgentShortReadBuffer=Short read from SSH agent
+sshAgentUnknownKey=SSH agent delivered a key that cannot be handled
+sshAgentWrongKeyLength=SSH agent delivered illogical key length {0} at offset {1} in buffer of length {2}
sshAgentWrongNumberOfKeys=Invalid number of SSH agent keys: {0}
sshClosingDown=Apache MINA sshd session factory is closing down; cannot create new ssh sessions on this factory
sshCommandTimeout={0} timed out after {1} seconds while opening the channel
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
index e2dbb4c..5100bc9 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
@@ -42,7 +42,6 @@
import org.apache.sshd.common.io.IoWriteFuture;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.DHFactory;
-import org.apache.sshd.common.kex.KexProposalOption;
import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.common.kex.extension.KexExtensionHandler;
import org.apache.sshd.common.kex.extension.KexExtensionHandler.AvailabilityPhase;
@@ -199,24 +198,6 @@ public void messageReceived(Readable buffer) throws Exception {
}
}
- @Override
- protected Map<KexProposalOption, String> setNegotiationResult(
- Map<KexProposalOption, String> guess) {
- Map<KexProposalOption, String> result = super.setNegotiationResult(
- guess);
- // This should be doable with a SessionListener, too, but I don't see
- // how to add a listener in time to catch the negotiation end for sure
- // given that the super-constructor already starts KEX.
- //
- // TODO: This override can be removed once we use sshd 2.8.0.
- if (log.isDebugEnabled()) {
- result.forEach((option, value) -> log.debug(
- "setNegotiationResult({}) Kex: {} = {}", this, //$NON-NLS-1$
- option.getDescription(), value));
- }
- return result;
- }
-
Set<String> getAllAvailableSignatureAlgorithms() {
Set<String> allAvailable = new HashSet<>();
BuiltinSignatures.VALUES.forEach(s -> allAvailable.add(s.getName()));
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
index c082a9a..96da0cc 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
@@ -12,25 +12,68 @@
import static java.text.MessageFormat.format;
import static org.eclipse.jgit.transport.SshConstants.PUBKEY_ACCEPTED_ALGORITHMS;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.SshAgentFactory;
+import org.apache.sshd.agent.SshAgentKeyConstraint;
import org.apache.sshd.client.auth.pubkey.KeyAgentIdentity;
import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity;
import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
+import org.apache.sshd.common.config.keys.u2f.SecurityKeyPublicKey;
import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.SshConstants;
+import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.StringUtils;
/**
* Custom {@link UserAuthPublicKey} implementation for handling SSH config
- * PubkeyAcceptedAlgorithms.
+ * PubkeyAcceptedAlgorithms and interaction with the SSH agent.
*/
public class JGitPublicKeyAuthentication extends UserAuthPublicKey {
+ private SshAgent agent;
+
+ private HostConfigEntry hostConfig;
+
+ private boolean addKeysToAgent;
+
+ private boolean askBeforeAdding;
+
+ private String skProvider;
+
+ private SshAgentKeyConstraint[] constraints;
+
JGitPublicKeyAuthentication(List<NamedFactory<Signature>> factories) {
super(factories);
}
@@ -43,7 +86,7 @@ public void init(ClientSession rawSession, String service)
+ rawSession.getClass().getCanonicalName());
}
JGitClientSession session = (JGitClientSession) rawSession;
- HostConfigEntry hostConfig = session.getHostConfigEntry();
+ hostConfig = session.getHostConfigEntry();
// Set signature algorithms for public key authentication
String pubkeyAlgos = hostConfig.getProperty(PUBKEY_ACCEPTED_ALGORITHMS);
if (!StringUtils.isEmptyOrNull(pubkeyAlgos)) {
@@ -64,46 +107,291 @@ public void init(ClientSession rawSession, String service)
// If we don't set signature factories here, the default ones from the
// session will be used.
super.init(session, service);
- // In sshd 2.7.0, we end up now with a key iterator that uses keys
- // provided by an ssh-agent even if IdentitiesOnly is true. So if
- // needed, filter out any KeyAgentIdentity.
- if (hostConfig.isIdentitiesOnly()) {
- Iterator<PublicKeyIdentity> original = keys;
- // The original iterator will already have gotten the identities
- // from the agent. Unfortunately there's nothing we can do about
- // that; it'll have to be fixed upstream. (As will, ultimately,
- // respecting isIdentitiesOnly().) At least we can simply not
- // use the keys the agent provided.
- //
- // See https://issues.apache.org/jira/browse/SSHD-1218
- keys = new Iterator<>() {
+ }
- private PublicKeyIdentity value;
+ @Override
+ protected Iterator<PublicKeyIdentity> createPublicKeyIterator(
+ ClientSession session, SignatureFactoriesManager manager)
+ throws Exception {
+ agent = getAgent(session);
+ if (agent != null) {
+ parseAddKeys(hostConfig);
+ if (addKeysToAgent) {
+ skProvider = hostConfig.getProperty(SshConstants.SECURITY_KEY_PROVIDER);
+ }
+ }
+ return new KeyIterator(session, manager);
+ }
+
+ @Override
+ protected PublicKeyIdentity resolveAttemptedPublicKeyIdentity(
+ ClientSession session, String service) throws Exception {
+ PublicKeyIdentity result = getNextKey(session, service);
+ // This fixes SSHD-1231. Can be removed once we're using Apache MINA
+ // sshd > 2.8.0.
+ //
+ // See https://issues.apache.org/jira/browse/SSHD-1231
+ currentAlgorithms.clear();
+ return result;
+ }
+
+ private PublicKeyIdentity getNextKey(ClientSession session, String service)
+ throws Exception {
+ PublicKeyIdentity id = super.resolveAttemptedPublicKeyIdentity(session,
+ service);
+ if (addKeysToAgent && id != null && !(id instanceof KeyAgentIdentity)) {
+ KeyPair key = id.getKeyIdentity();
+ if (key != null && key.getPublic() != null
+ && key.getPrivate() != null) {
+ // We've just successfully loaded a key that wasn't in the
+ // agent. Add it to the agent.
+ //
+ // Keys are added after loading, as in OpenSSH. The alternative
+ // might be to add a key only after (partially) successful
+ // authentication?
+ PublicKey pk = key.getPublic();
+ String fingerprint = KeyUtils.getFingerPrint(pk);
+ String keyType = KeyUtils.getKeyType(key);
+ try {
+ // Check that the key is not in the agent already.
+ if (agentHasKey(pk)) {
+ return id;
+ }
+ if (askBeforeAdding
+ && (session instanceof JGitClientSession)) {
+ CredentialsProvider provider = ((JGitClientSession) session)
+ .getCredentialsProvider();
+ CredentialItem.YesNoType question = new CredentialItem.YesNoType(
+ format(SshdText
+ .get().pubkeyAuthAddKeyToAgentQuestion,
+ keyType, fingerprint));
+ boolean result = provider != null
+ && provider.supports(question)
+ && provider.get(getUri(), question);
+ if (!result || !question.getValue()) {
+ // Don't add the key.
+ return id;
+ }
+ }
+ SshAgentKeyConstraint[] rules = constraints;
+ if (pk instanceof SecurityKeyPublicKey && !StringUtils.isEmptyOrNull(skProvider)) {
+ rules = Arrays.copyOf(rules, rules.length + 1);
+ rules[rules.length - 1] =
+ new SshAgentKeyConstraint.FidoProviderExtension(skProvider);
+ }
+ // Unfortunately a comment associated with the key is lost
+ // by Apache MINA sshd, and there is also no way to get the
+ // original file name for keys loaded from a file. So add it
+ // without comment.
+ agent.addIdentity(key, null, rules);
+ } catch (IOException e) {
+ // Do not re-throw: we don't want authentication to fail if
+ // we cannot add the key to the agent.
+ log.error(
+ format(SshdText.get().pubkeyAuthAddKeyToAgentError,
+ keyType, fingerprint),
+ e);
+ // Note that as of Win32-OpenSSH 8.6 and Pageant 0.76,
+ // neither can handle key constraints. Pageant fails
+ // gracefully, not adding the key and returning
+ // SSH_AGENT_FAILURE. Win32-OpenSSH closes the connection
+ // without even returning a failure message, which violates
+ // the SSH agent protocol and makes all subsequent requests
+ // to the agent fail.
+ }
+ }
+ }
+ return id;
+ }
+
+ private boolean agentHasKey(PublicKey pk) throws IOException {
+ Iterable<? extends Map.Entry<PublicKey, String>> ids = agent
+ .getIdentities();
+ if (ids == null) {
+ return false;
+ }
+ Iterator<? extends Map.Entry<PublicKey, String>> iter = ids.iterator();
+ while (iter.hasNext()) {
+ if (KeyUtils.compareKeys(iter.next().getKey(), pk)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private URIish getUri() {
+ String uri = SshConstants.SSH_SCHEME + "://"; //$NON-NLS-1$
+ String userName = hostConfig.getUsername();
+ if (!StringUtils.isEmptyOrNull(userName)) {
+ uri += userName + '@';
+ }
+ uri += hostConfig.getHost();
+ int port = hostConfig.getPort();
+ if (port > 0 && port != SshConstants.SSH_DEFAULT_PORT) {
+ uri += ":" + port; //$NON-NLS-1$
+ }
+ try {
+ return new URIish(uri);
+ } catch (URISyntaxException e) {
+ log.error(e.getLocalizedMessage(), e);
+ }
+ return new URIish();
+ }
+
+ private SshAgent getAgent(ClientSession session) throws Exception {
+ FactoryManager manager = Objects.requireNonNull(
+ session.getFactoryManager(), "No session factory manager"); //$NON-NLS-1$
+ SshAgentFactory factory = manager.getAgentFactory();
+ if (factory == null) {
+ return null;
+ }
+ return factory.createClient(session, manager);
+ }
+
+ private void parseAddKeys(HostConfigEntry config) {
+ String value = config.getProperty(SshConstants.ADD_KEYS_TO_AGENT);
+ if (StringUtils.isEmptyOrNull(value)) {
+ addKeysToAgent = false;
+ return;
+ }
+ String[] values = value.split(","); //$NON-NLS-1$
+ List<SshAgentKeyConstraint> rules = new ArrayList<>(2);
+ switch (values[0]) {
+ case "yes": //$NON-NLS-1$
+ addKeysToAgent = true;
+ break;
+ case "no": //$NON-NLS-1$
+ addKeysToAgent = false;
+ break;
+ case "ask": //$NON-NLS-1$
+ addKeysToAgent = true;
+ askBeforeAdding = true;
+ break;
+ case "confirm": //$NON-NLS-1$
+ addKeysToAgent = true;
+ rules.add(SshAgentKeyConstraint.CONFIRM);
+ if (values.length > 1) {
+ int seconds = OpenSshConfigFile.timeSpec(values[1]);
+ if (seconds > 0) {
+ rules.add(new SshAgentKeyConstraint.LifeTime(seconds));
+ }
+ }
+ break;
+ default:
+ int seconds = OpenSshConfigFile.timeSpec(values[0]);
+ if (seconds > 0) {
+ addKeysToAgent = true;
+ rules.add(new SshAgentKeyConstraint.LifeTime(seconds));
+ }
+ break;
+ }
+ constraints = rules.toArray(new SshAgentKeyConstraint[0]);
+ }
+
+ @Override
+ protected void releaseKeys() throws IOException {
+ addKeysToAgent = false;
+ askBeforeAdding = false;
+ skProvider = null;
+ constraints = null;
+ try {
+ if (agent != null) {
+ try {
+ agent.close();
+ } finally {
+ agent = null;
+ }
+ }
+ } finally {
+ super.releaseKeys();
+ }
+ }
+
+ private class KeyIterator extends UserAuthPublicKeyIterator {
+
+ private Iterable<? extends Map.Entry<PublicKey, String>> agentKeys;
+
+ // If non-null, all the public keys from explicitly given key files. Any
+ // agent key not matching one of these public keys will be ignored in
+ // getIdentities().
+ private Collection<PublicKey> identityFiles;
+
+ public KeyIterator(ClientSession session,
+ SignatureFactoriesManager manager)
+ throws Exception {
+ super(session, manager);
+ }
+
+ private List<PublicKey> getExplicitKeys(
+ Collection<String> explicitFiles) {
+ if (explicitFiles == null) {
+ return null;
+ }
+ return explicitFiles.stream().map(s -> {
+ try {
+ Path p = Paths.get(s + ".pub"); //$NON-NLS-1$
+ if (Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS)) {
+ return AuthorizedKeyEntry.readAuthorizedKeys(p).get(0)
+ .resolvePublicKey(null,
+ PublicKeyEntryResolver.IGNORING);
+ }
+ } catch (InvalidPathException | IOException
+ | GeneralSecurityException e) {
+ log.warn(format(SshdText.get().cannotReadPublicKey, s), e);
+ }
+ return null;
+ }).filter(Objects::nonNull).collect(Collectors.toList());
+ }
+
+ @Override
+ protected Iterable<KeyAgentIdentity> initializeAgentIdentities(
+ ClientSession session) throws IOException {
+ if (agent == null) {
+ return null;
+ }
+ agentKeys = agent.getIdentities();
+ if (hostConfig != null && hostConfig.isIdentitiesOnly()) {
+ identityFiles = getExplicitKeys(hostConfig.getIdentities());
+ }
+ return () -> new Iterator<>() {
+
+ private final Iterator<? extends Map.Entry<PublicKey, String>> iter = agentKeys
+ .iterator();
+
+ private Map.Entry<PublicKey, String> next;
@Override
public boolean hasNext() {
- if (value != null) {
- return true;
- }
- PublicKeyIdentity next = null;
- while (original.hasNext()) {
- next = original.next();
- if (!(next instanceof KeyAgentIdentity)) {
- value = next;
+ while (next == null && iter.hasNext()) {
+ Map.Entry<PublicKey, String> val = iter.next();
+ PublicKey pk = val.getKey();
+ // This checks against all explicit keys for any agent
+ // key, but since identityFiles.size() is typically 1,
+ // it should be fine.
+ if (identityFiles == null || identityFiles.stream()
+ .anyMatch(k -> KeyUtils.compareKeys(k, pk))) {
+ next = val;
return true;
}
+ if (log.isTraceEnabled()) {
+ log.trace(
+ "Ignoring SSH agent {} key not in explicit IdentityFile in SSH config: {}", //$NON-NLS-1$
+ KeyUtils.getKeyType(pk),
+ KeyUtils.getFingerPrint(pk));
+ }
}
- return false;
+ return next != null;
}
@Override
- public PublicKeyIdentity next() {
- if (hasNext()) {
- PublicKeyIdentity result = value;
- value = null;
- return result;
+ public KeyAgentIdentity next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
}
- throw new NoSuchElementException();
+ KeyAgentIdentity result = new KeyAgentIdentity(agent,
+ next.getKey(), next.getValue());
+ next = null;
+ return result;
}
};
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
index 00ee62d..19ad85c 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -30,6 +30,7 @@ public static SshdText get() {
/***/ public String authenticationCanceled;
/***/ public String authenticationOnClosedSession;
/***/ public String closeListenerFailed;
+ /***/ public String cannotReadPublicKey;
/***/ public String configInvalidPath;
/***/ public String configInvalidPattern;
/***/ public String configInvalidPositive;
@@ -98,6 +99,8 @@ public static SshdText get() {
/***/ public String proxySocksUnexpectedMessage;
/***/ public String proxySocksUnexpectedVersion;
/***/ public String proxySocksUsernameTooLong;
+ /***/ public String pubkeyAuthAddKeyToAgentError;
+ /***/ public String pubkeyAuthAddKeyToAgentQuestion;
/***/ public String pubkeyAuthWrongCommand;
/***/ public String pubkeyAuthWrongKey;
/***/ public String pubkeyAuthWrongSignatureAlgorithm;
@@ -106,9 +109,13 @@ public static SshdText get() {
/***/ public String serverIdWithNul;
/***/ public String sessionCloseFailed;
/***/ public String sessionWithoutUsername;
+ /***/ public String sshAgentEdDSAFormatError;
+ /***/ public String sshAgentPayloadLengthError;
/***/ public String sshAgentReplyLengthError;
/***/ public String sshAgentReplyUnexpected;
/***/ public String sshAgentShortReadBuffer;
+ /***/ public String sshAgentUnknownKey;
+ /***/ public String sshAgentWrongKeyLength;
/***/ public String sshAgentWrongNumberOfKeys;
/***/ public String sshClosingDown;
/***/ public String sshCommandTimeout;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/JGitSshAgentFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/JGitSshAgentFactory.java
index 1ed2ab9..a0ffd54 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/JGitSshAgentFactory.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/JGitSshAgentFactory.java
@@ -17,10 +17,14 @@
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.agent.SshAgentServer;
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.channel.ChannelFactory;
import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.transport.sshd.JGitClientSession;
+import org.eclipse.jgit.transport.SshConstants;
import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory;
/**
@@ -49,18 +53,24 @@ public JGitSshAgentFactory(@NonNull ConnectorFactory factory,
@Override
public List<ChannelFactory> getChannelForwardingFactories(
FactoryManager manager) {
- // No agent forwarding supported yet.
+ // No agent forwarding supported.
return Collections.emptyList();
}
@Override
- public SshAgent createClient(FactoryManager manager) throws IOException {
- // sshd 2.8.0 will pass us the session here. At that point, we can get
- // the HostConfigEntry and extract and handle the IdentityAgent setting.
- // For now, pass null to let the ConnectorFactory do its default
- // behavior (Pageant on Windows, SSH_AUTH_SOCK on Unixes with the
- // jgit-builtin factory).
- return new SshAgentClient(factory.create(null, homeDir));
+ public SshAgent createClient(Session session, FactoryManager manager)
+ throws IOException {
+ String identityAgent = null;
+ if (session instanceof JGitClientSession) {
+ HostConfigEntry hostConfig = ((JGitClientSession) session)
+ .getHostConfigEntry();
+ identityAgent = hostConfig.getProperty(SshConstants.IDENTITY_AGENT,
+ null);
+ }
+ if (SshConstants.NONE.equals(identityAgent)) {
+ return null;
+ }
+ return new SshAgentClient(factory.create(identityAgent, homeDir));
}
@Override
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/SshAgentClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/SshAgentClient.java
index 08483e4..cbcb4d2 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/SshAgentClient.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/agent/SshAgentClient.java
@@ -11,10 +11,12 @@
import java.io.IOException;
import java.security.KeyPair;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.text.MessageFormat;
import java.util.AbstractMap;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -22,21 +24,27 @@
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentConstants;
+import org.apache.sshd.agent.SshAgentKeyConstraint;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferException;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.buffer.keys.BufferPublicKeyParser;
+import org.apache.sshd.common.util.io.der.DERParser;
import org.eclipse.jgit.internal.transport.sshd.SshdText;
import org.eclipse.jgit.transport.sshd.agent.Connector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * A client for an SSH2 agent. This client supports only querying identities and
- * signature requests.
+ * A client for an SSH2 agent. This client supports querying identities,
+ * signature requests, and adding keys to an agent (with or without
+ * constraints). Removing keys is not supported, and the older SSH1 protocol is
+ * not supported.
*
* @see <a href="https://tools.ietf.org/html/draft-miller-ssh-agent-04">SSH
* Agent Protocol, RFC draft</a>
@@ -72,11 +80,18 @@ private boolean open(boolean debugging) throws IOException {
}
return false;
}
- boolean connected = connector != null && connector.connect();
- if (!connected) {
- if (debugging) {
- LOG.debug("No SSH agent (SSH_AUTH_SOCK not set)"); //$NON-NLS-1$
+ boolean connected;
+ try {
+ connected = connector != null && connector.connect();
+ if (!connected && debugging) {
+ LOG.debug("No SSH agent"); //$NON-NLS-1$
}
+ } catch (IOException e) {
+ // Agent not running?
+ if (debugging) {
+ LOG.debug("No SSH agent", e); //$NON-NLS-1$
+ }
+ throw e;
}
return connected;
}
@@ -127,14 +142,17 @@ public Iterable<? extends Map.Entry<PublicKey, String>> getIdentities()
List<Map.Entry<PublicKey, String>> keys = new ArrayList<>(
numberOfKeys);
for (int i = 0; i < numberOfKeys; i++) {
- PublicKey key = reply.getPublicKey();
+ PublicKey key = readKey(reply);
String comment = reply.getString();
- if (tracing) {
- LOG.trace("Got SSH agent {} key: {} {}", //$NON-NLS-1$
- KeyUtils.getKeyType(key),
- KeyUtils.getFingerPrint(key), comment);
+ if (key != null) {
+ if (tracing) {
+ LOG.trace("Got SSH agent {} key: {} {}", //$NON-NLS-1$
+ KeyUtils.getKeyType(key),
+ KeyUtils.getFingerPrint(key), comment);
+ }
+ keys.add(new AbstractMap.SimpleImmutableEntry<>(key,
+ comment));
}
- keys.add(new AbstractMap.SimpleImmutableEntry<>(key, comment));
}
return keys;
} catch (BufferException e) {
@@ -216,6 +234,222 @@ public Iterable<? extends Map.Entry<PublicKey, String>> getIdentities()
}
}
+ @Override
+ public void addIdentity(KeyPair key, String comment,
+ SshAgentKeyConstraint... constraints) throws IOException {
+ boolean debugging = LOG.isDebugEnabled();
+ if (!open(debugging)) {
+ return;
+ }
+
+ // Neither Pageant 0.76 nor Win32-OpenSSH 8.6 support command
+ // SSH2_AGENTC_ADD_ID_CONSTRAINED. Adding a key with constraints will
+ // fail. The only work-around for users is not to use "confirm" or "time
+ // spec" with AddKeysToAgent, and not to use sk-* keys.
+ //
+ // With a true OpenSSH SSH agent, key constraints work.
+ byte cmd = (constraints != null && constraints.length > 0)
+ ? SshAgentConstants.SSH2_AGENTC_ADD_ID_CONSTRAINED
+ : SshAgentConstants.SSH2_AGENTC_ADD_IDENTITY;
+ byte[] message = null;
+ ByteArrayBuffer msg = new ByteArrayBuffer();
+ try {
+ msg.putInt(0);
+ msg.putByte(cmd);
+ String keyType = KeyUtils.getKeyType(key);
+ if (KeyPairProvider.SSH_ED25519.equals(keyType)) {
+ // Apache MINA sshd 2.8.0 lacks support for writing ed25519
+ // private keys to a buffer.
+ putEd25519Key(msg, key);
+ } else {
+ msg.putKeyPair(key);
+ }
+ msg.putString(comment == null ? "" : comment); //$NON-NLS-1$
+ if (constraints != null) {
+ for (SshAgentKeyConstraint constraint : constraints) {
+ constraint.put(msg);
+ }
+ }
+ if (debugging) {
+ LOG.debug(
+ "addIdentity: adding {} key {} to SSH agent; comment {}", //$NON-NLS-1$
+ keyType, KeyUtils.getFingerPrint(key.getPublic()),
+ comment);
+ }
+ message = msg.getCompactData();
+ } finally {
+ // The message contains the private key data, so clear intermediary
+ // data ASAP.
+ msg.clear();
+ }
+ Buffer reply;
+ try {
+ reply = rpc(cmd, message);
+ } finally {
+ Arrays.fill(message, (byte) 0);
+ }
+ int replyLength = reply.available();
+ if (replyLength != 1) {
+ throw new SshException(MessageFormat.format(
+ SshdText.get().sshAgentReplyUnexpected,
+ MessageFormat.format(
+ SshdText.get().sshAgentPayloadLengthError,
+ Integer.valueOf(1), Integer.valueOf(replyLength))));
+
+ }
+ cmd = reply.getByte();
+ if (cmd != SshAgentConstants.SSH_AGENT_SUCCESS) {
+ throw new SshException(
+ MessageFormat.format(SshdText.get().sshAgentReplyUnexpected,
+ SshAgentConstants.getCommandMessageName(cmd)));
+ }
+ }
+
+ /**
+ * Writes an ed25519 {@link KeyPair} to a {@link Buffer}. OpenSSH specifies
+ * that it expects the 32 public key bytes, followed by 64 bytes formed by
+ * concatenating the 32 private key bytes with the 32 public key bytes.
+ *
+ * @param msg
+ * {@link Buffer} to write to
+ * @param key
+ * {@link KeyPair} to write
+ * @throws IOException
+ * if the private key cannot be written
+ */
+ private static void putEd25519Key(Buffer msg, KeyPair key)
+ throws IOException {
+ Buffer tmp = new ByteArrayBuffer(36);
+ tmp.putRawPublicKeyBytes(key.getPublic());
+ byte[] publicBytes = tmp.getBytes();
+ msg.putString(KeyPairProvider.SSH_ED25519);
+ msg.putBytes(publicBytes);
+ // Next is the concatenation of the 32 byte private key value with the
+ // 32 bytes of the public key.
+ PrivateKey pk = key.getPrivate();
+ String format = pk.getFormat();
+ if (!"PKCS#8".equalsIgnoreCase(format)) { //$NON-NLS-1$
+ throw new IOException(MessageFormat
+ .format(SshdText.get().sshAgentEdDSAFormatError, format));
+ }
+ byte[] privateBytes = null;
+ byte[] encoded = pk.getEncoded();
+ try {
+ privateBytes = asn1Parse(encoded, 32);
+ byte[] combined = Arrays.copyOf(privateBytes, 64);
+ Arrays.fill(privateBytes, (byte) 0);
+ privateBytes = combined;
+ System.arraycopy(publicBytes, 0, privateBytes, 32, 32);
+ msg.putBytes(privateBytes);
+ } finally {
+ if (privateBytes != null) {
+ Arrays.fill(privateBytes, (byte) 0);
+ }
+ Arrays.fill(encoded, (byte) 0);
+ }
+ }
+
+ /**
+ * Extracts the private key bytes from an encoded ed25519 private key by
+ * parsing the bytes as ASN.1 according to RFC 5958 (PKCS #8 encoding):
+ *
+ * <pre>
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * ...
+ * }
+ *
+ * Version ::= INTEGER
+ * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ * PrivateKey ::= OCTET STRING
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ * </pre>
+ * <p>
+ * and RFC 8410: "... when encoding a OneAsymmetricKey object, the private
+ * key is wrapped in a CurvePrivateKey object and wrapped by the OCTET
+ * STRING of the 'privateKey' field."
+ * </p>
+ *
+ * <pre>
+ * CurvePrivateKey ::= OCTET STRING
+ * </pre>
+ *
+ * @param encoded
+ * encoded private key to extract the private key bytes from
+ * @param n
+ * number of bytes expected
+ * @return the extracted private key bytes; of length {@code n}
+ * @throws IOException
+ * if the private key cannot be extracted
+ * @see <a href="https://tools.ietf.org/html/rfc5958">RFC 5958</a>
+ * @see <a href="https://tools.ietf.org/html/rfc8410">RFC 8410</a>
+ */
+ private static byte[] asn1Parse(byte[] encoded, int n) throws IOException {
+ byte[] privateKey = null;
+ try (DERParser byteParser = new DERParser(encoded);
+ DERParser oneAsymmetricKey = byteParser.readObject()
+ .createParser()) {
+ oneAsymmetricKey.readObject(); // skip version
+ oneAsymmetricKey.readObject(); // skip algorithm identifier
+ privateKey = oneAsymmetricKey.readObject().getValue();
+ // The last n bytes of this must be the private key bytes
+ return Arrays.copyOfRange(privateKey,
+ privateKey.length - n, privateKey.length);
+ } finally {
+ if (privateKey != null) {
+ Arrays.fill(privateKey, (byte) 0);
+ }
+ }
+ }
+
+ /**
+ * A safe version of {@link Buffer#getPublicKey()}. Upon return the
+ * buffers's read position is always after the key blob; any exceptions
+ * thrown by trying to read the key are logged and <em>not</em> propagated.
+ * <p>
+ * This is needed because an SSH agent might contain and deliver keys that
+ * we cannot handle (for instance ed448 keys).
+ * </p>
+ *
+ * @param buffer
+ * to read the key from
+ * @return the {@link PublicKey}, or {@code null} if the key could not be
+ * read
+ * @throws BufferException
+ * if the length of the key blob cannot be read or is corrupted
+ */
+ private static PublicKey readKey(Buffer buffer) throws BufferException {
+ int endOfBuffer = buffer.wpos();
+ int keyLength = buffer.getInt();
+ int afterKey = buffer.rpos() + keyLength;
+ if (keyLength <= 0 || afterKey > endOfBuffer) {
+ throw new BufferException(
+ MessageFormat.format(SshdText.get().sshAgentWrongKeyLength,
+ Integer.toString(keyLength),
+ Integer.toString(buffer.rpos()),
+ Integer.toString(endOfBuffer)));
+ }
+ // Limit subsequent reads to the public key blob
+ buffer.wpos(afterKey);
+ try {
+ return buffer.getRawPublicKey(BufferPublicKeyParser.DEFAULT);
+ } catch (Exception e) {
+ LOG.warn(SshdText.get().sshAgentUnknownKey, e);
+ return null;
+ } finally {
+ // Restore real buffer end
+ buffer.wpos(endOfBuffer);
+ // Set the read position to after this key, even if failed
+ buffer.rpos(afterKey);
+ }
+ }
+
private Buffer rpc(byte command, byte[] message) throws IOException {
return new ByteArrayBuffer(connector.rpc(command, message));
}
@@ -230,11 +464,6 @@ public boolean isOpen() {
}
@Override
- public void addIdentity(KeyPair key, String comment) throws IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
public void removeIdentity(PublicKey key) throws IOException {
throw new UnsupportedOperationException();
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
index c270b44..b742f5e 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java
@@ -51,6 +51,7 @@
import org.apache.sshd.sftp.common.SftpException;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
import org.eclipse.jgit.internal.transport.sshd.SshdText;
import org.eclipse.jgit.transport.FtpChannel;
@@ -138,7 +139,11 @@ private ClientSession connect(URIish target, List<URIish> jumps,
JGitSshClient.LOCAL_FORWARD_ADDRESS,
portForward.getBoundAddress());
}
- resultSession = connect(hostConfig, context, timeout);
+ int timeoutInSec = OpenSshConfigFile.timeSpec(
+ hostConfig.getProperty(SshConstants.CONNECT_TIMEOUT));
+ resultSession = connect(hostConfig, context,
+ timeoutInSec > 0 ? Duration.ofSeconds(timeoutInSec)
+ : timeout);
if (proxySession != null) {
final PortForwardingTracker tracker = portForward;
final ClientSession pSession = proxySession;
diff --git a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
index 52e69bd..4a08940 100644
--- a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
@@ -3,18 +3,18 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ssh.jsch.test
Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: com.jcraft.jsch;version="[0.1.54,0.2.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit.ssh;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.ssh.jsch;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit.ssh;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.ssh.jsch;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
org.hamcrest;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.experimental.theories;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.ssh.jsch.test/pom.xml b/org.eclipse.jgit.ssh.jsch.test/pom.xml
index 6f199e6..ca1e742 100644
--- a/org.eclipse.jgit.ssh.jsch.test/pom.xml
+++ b/org.eclipse.jgit.ssh.jsch.test/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.jsch.test</artifactId>
diff --git a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF
index ed997fb..332d981 100644
--- a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ssh.jsch
Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch;singleton:=true
-Fragment-Host: org.eclipse.jgit;bundle-version="[6.0.1,6.1.0)"
+Fragment-Host: org.eclipse.jgit;bundle-version="[6.1.1,6.2.0)"
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="6.0.1"
+Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="6.1.1"
Import-Package: com.jcraft.jsch;version="[0.1.37,0.2.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.ssh;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.io;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
org.slf4j;version="[1.7.0,2.0.0)"
diff --git a/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF
index 3c3f2b1..b56bb7c 100644
--- a/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.ssh.jsch - Sources
Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.jsch/pom.xml b/org.eclipse.jgit.ssh.jsch/pom.xml
index 2a5f9b8..3b6d66c 100644
--- a/org.eclipse.jgit.ssh.jsch/pom.xml
+++ b/org.eclipse.jgit.ssh.jsch/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.jsch</artifactId>
diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD
index 9e787fe..6f6c88c 100644
--- a/org.eclipse.jgit.test/BUILD
+++ b/org.eclipse.jgit.test/BUILD
@@ -13,6 +13,7 @@
) + [PKG + c for c in [
"api/AbstractRemoteCommandTest.java",
"diff/AbstractDiffTestCase.java",
+ "internal/diffmergetool/ExternalToolTestCase.java",
"internal/revwalk/ObjectReachabilityTestCase.java",
"internal/revwalk/ReachabilityCheckerTestCase.java",
"internal/storage/file/GcTestCase.java",
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 0469113..581395d 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.test
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -16,60 +16,61 @@
org.apache.commons.compress.compressors.gzip;version="[1.15.0,2.0)",
org.apache.commons.compress.compressors.xz;version="[1.15.0,2.0)",
org.assertj.core.api;version="[3.14.0,4.0.0)",
- org.eclipse.jgit.annotations;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.api.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.archive;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.attributes;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.awtui;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.blame;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.diff;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.dircache;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.events;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.fnmatch;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.gitrepo;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.hooks;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.ignore;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.ignore.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.fsck;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.io;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.pack;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.connectivity;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.parser;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.internal.transport.ssh;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.junit.time;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lfs;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.logging;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.merge;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.notes;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.patch;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.pgm;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.pgm.internal;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revplot;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.file;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.storage.pack;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.submodule;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.http;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport.resolver;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.io;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util.sha1;version="[6.0.1,6.1.0)",
+ org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.archive;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.attributes;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.awtui;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.blame;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.diff;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.dircache;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.events;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.fnmatch;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.gitrepo;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.hooks;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.ignore;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.ignore.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.fsck;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.io;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.connectivity;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.junit.time;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lfs;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.logging;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.merge;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.notes;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.patch;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.pgm;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.pgm.internal;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revplot;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.storage.pack;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.submodule;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util.sha1;version="[6.1.1,6.2.0)",
org.hamcrest;version="[1.1.0,3.0.0)",
org.hamcrest.collection;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 3cab362..6b66919 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -19,7 +19,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
index 867310b..584d149 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
@@ -32,6 +32,7 @@
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
import org.junit.Test;
@@ -402,7 +403,9 @@ public void testModifyW() throws Exception {
public void testAddM1() throws Exception {
ApplyResult result = init("M1", false, true);
assertEquals(1, result.getUpdatedFiles().size());
- assertTrue(result.getUpdatedFiles().get(0).canExecute());
+ if (FS.DETECTED.supportsExecute()) {
+ assertTrue(FS.DETECTED.canExecute(result.getUpdatedFiles().get(0)));
+ }
checkFile(new File(db.getWorkTree(), "M1"),
b.getString(0, b.size(), false));
}
@@ -411,7 +414,9 @@ public void testAddM1() throws Exception {
public void testModifyM2() throws Exception {
ApplyResult result = init("M2", true, true);
assertEquals(1, result.getUpdatedFiles().size());
- assertTrue(result.getUpdatedFiles().get(0).canExecute());
+ if (FS.DETECTED.supportsExecute()) {
+ assertTrue(FS.DETECTED.canExecute(result.getUpdatedFiles().get(0)));
+ }
checkFile(new File(db.getWorkTree(), "M2"),
b.getString(0, b.size(), false));
}
@@ -420,7 +425,10 @@ public void testModifyM2() throws Exception {
public void testModifyM3() throws Exception {
ApplyResult result = init("M3", true, true);
assertEquals(1, result.getUpdatedFiles().size());
- assertFalse(result.getUpdatedFiles().get(0).canExecute());
+ if (FS.DETECTED.supportsExecute()) {
+ assertFalse(
+ FS.DETECTED.canExecute(result.getUpdatedFiles().get(0)));
+ }
checkFile(new File(db.getWorkTree(), "M3"),
b.getString(0, b.size(), false));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
index e7ed102..87be813 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
@@ -71,6 +71,7 @@ public void setUp() throws Exception {
private Git setUpRepoWithRemote() throws Exception {
Repository remoteRepository = createWorkRepository();
+ addRepoToClose(remoteRepository);
try (Git remoteGit = new Git(remoteRepository)) {
// commit something
writeTrashFile("Test.txt", "Hello world");
@@ -85,6 +86,7 @@ private Git setUpRepoWithRemote() throws Exception {
rup.forceUpdate();
Repository localRepository = createWorkRepository();
+ addRepoToClose(localRepository);
Git localGit = new Git(localRepository);
StoredConfig config = localRepository.getConfig();
RemoteConfig rc = new RemoteConfig(config, "origin");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index e520732..ab0184b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -292,6 +292,7 @@ public void testCheckoutAnnotatedTag() throws Exception {
@Test
public void testCheckoutRemoteTrackingWithUpstream() throws Exception {
Repository db2 = createRepositoryWithRemote();
+ addRepoToClose(db2);
Git.wrap(db2).checkout().setCreateBranch(true).setName("test")
.setStartPoint("origin/test")
@@ -311,6 +312,7 @@ public void testCheckoutRemoteTrackingWithUpstream() throws Exception {
@Test
public void testCheckoutRemoteTrackingWithoutLocalBranch() throws Exception {
Repository db2 = createRepositoryWithRemote();
+ addRepoToClose(db2);
// checkout remote tracking branch in second repository
// (no local branches exist yet in second repository)
@@ -868,7 +870,7 @@ public void testNonDeletableFilesOnWindows()
coCommand.setName(crudCommit.getName()).call();
CheckoutResult result = coCommand.getResult();
assertEquals(Status.NONDELETED, result.getStatus());
- assertEquals("[Test.txt, toBeDeleted.txt]",
+ assertEquals("[toBeDeleted.txt]",
result.getRemovedList().toString());
assertEquals("[toBeCreated.txt, toBeModified.txt]",
result.getModifiedList().toString());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
index f4f0ecd..0d38197 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
@@ -175,7 +175,8 @@ public void testCherryPickConflictResolution() throws Exception {
assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
- assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg());
+ assertEquals("side\n\n# Conflicts:\n#\ta\n",
+ db.readMergeCommitMsg());
assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
.exists());
assertEquals(sideCommit.getId(), db.readCherryPickHead());
@@ -207,7 +208,7 @@ public void testCherryPickConflictResolutionNoCommit() throws Exception {
String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n";
assertEquals(expected, read("a"));
assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
- assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg());
+ assertEquals("side\n\n# Conflicts:\n#\ta\n", db.readMergeCommitMsg());
assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
.exists());
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
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 8084505..35de73e 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
@@ -46,6 +46,7 @@
import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.submodule.SubmoduleWalk;
@@ -515,6 +516,62 @@ public void commitAmendWithAuthorShouldUseIt() throws Exception {
}
@Test
+ public void commitMessageVerbatim() throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit committed = git.commit().setMessage("#initial commit")
+ .call();
+
+ assertEquals("#initial commit", committed.getFullMessage());
+ }
+ }
+
+ @Test
+ public void commitMessageStrip() throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit committed = git.commit().setMessage(
+ "#Comment\ninitial commit\t\n\n commit body \n \t#another comment")
+ .setCleanupMode(CleanupMode.STRIP).call();
+
+ assertEquals("initial commit\n\n commit body",
+ committed.getFullMessage());
+ }
+ }
+
+ @Test
+ public void commitMessageDefault() throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit committed = git.commit().setMessage(
+ "#Comment\ninitial commit\t\n\n commit body \n\n\n \t#another comment ")
+ .setCleanupMode(CleanupMode.DEFAULT).call();
+
+ assertEquals("initial commit\n\n commit body",
+ committed.getFullMessage());
+ }
+ }
+
+ @Test
+ public void commitMessageDefaultWhitespace() throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit committed = git.commit().setMessage(
+ "#Comment\ninitial commit\t\n\n commit body \n\n\n \t#another comment ")
+ .setCleanupMode(CleanupMode.DEFAULT).setDefaultClean(false)
+ .call();
+
+ assertEquals(
+ "#Comment\ninitial commit\n\n commit body\n\n \t#another comment",
+ committed.getFullMessage());
+ }
+ }
+
+ @Test
public void commitEmptyCommits() throws Exception {
try (Git git = new Git(db)) {
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 b460e3f..ab87fa9 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
@@ -10,9 +10,10 @@
package org.eclipse.jgit.api;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.BufferedWriter;
@@ -100,6 +101,12 @@ public void testDescribe() throws Exception {
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*"));
+
+ assertEquals("bob-t2", describe(c4, false, true, 0));
+ assertEquals("bob-t2-1-g3e56", describe(c4, false, true, 1));
+ assertEquals("bob-t2-1-g3e56", describe(c4, false, true, -10));
+ assertEquals("bob-t2-1-g3e563c55927905f21e3bc7c00a3d83a31bf4ed3a",
+ describe(c4, false, true, 50));
} else {
assertEquals(null, describe(c2));
assertEquals(null, describe(c3));
@@ -108,6 +115,18 @@ public void testDescribe() throws Exception {
assertEquals("3747db3", describe(c2, false, true));
assertEquals("44579eb", describe(c3, false, true));
assertEquals("3e563c5", describe(c4, false, true));
+
+ assertEquals("3747db3267", describe(c2, false, true, 10));
+ assertEquals("44579ebe7f", describe(c3, false, true, 10));
+ assertEquals("3e563c5592", describe(c4, false, true, 10));
+
+ assertEquals("3e56", describe(c4, false, true, -10));
+ assertEquals("3e56", describe(c4, false, true, 0));
+ assertEquals("3e56", describe(c4, false, true, 2));
+ assertEquals("3e563c55927905f21e3bc7c00a3d83a31bf4ed3a",
+ describe(c4, false, true, 40));
+ assertEquals("3e563c55927905f21e3bc7c00a3d83a31bf4ed3a",
+ describe(c4, false, true, 42));
}
// test default target
@@ -474,10 +493,15 @@ private static void touch(File f, String contents) throws Exception {
}
}
+ private String describe(ObjectId c1, boolean longDesc, boolean always,
+ int abbrev) throws GitAPIException, IOException {
+ return git.describe().setTarget(c1).setTags(describeUseAllTags)
+ .setLong(longDesc).setAlways(always).setAbbrev(abbrev).call();
+ }
+
private String describe(ObjectId c1, boolean longDesc, boolean always)
throws GitAPIException, IOException {
- return git.describe().setTarget(c1).setTags(describeUseAllTags)
- .setLong(longDesc).setAlways(always).call();
+ return describe(c1, longDesc, always, OBJECT_ID_ABBREV_STRING_LENGTH);
}
private String describe(ObjectId c1) throws GitAPIException, IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
index d0dfd1a..b937b1f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
@@ -1,40 +1,11 @@
/*
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ * Copyright (C) 2015, 2022 Ivan Motsch <ivan.motsch@bsiag.com> and others
*
- * 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
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://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.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.api;
@@ -173,15 +144,22 @@ private static class ActualEntry {
private DirCache dirCache;
+ private boolean isDefaultCrLf() {
+ String eol = mockSystemReader.getProperty("line.separator");
+ return "\r\n".equals(eol);
+ }
+
@Test
public void testDefaultSetup() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(null, null, null, null, "* text=auto");
collectRepositoryState();
assertEquals("text=auto", entryCRLF.attrs);
- checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
+ // eol=native is the default!
+ String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
+ checkEntryContent(entryCRLF, expected, CONTENT_LF);
+ checkEntryContent(entryLF, expected, CONTENT_LF);
+ checkEntryContent(entryMixed, expected, CONTENT_LF);
}
public void checkEntryContent(ActualEntry entry, String fileContent,
@@ -199,9 +177,11 @@ public void test_ConfigAutoCRLF_false() throws Exception {
setupGitAndDoHardReset(AutoCRLF.FALSE, null, null, null, "* text=auto");
collectRepositoryState();
assertEquals("text=auto", entryCRLF.attrs);
- checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
+ // eol=native is the default!
+ String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
+ checkEntryContent(entryCRLF, expected, CONTENT_LF);
+ checkEntryContent(entryLF, expected, CONTENT_LF);
+ checkEntryContent(entryMixed, expected, CONTENT_LF);
}
@Test
@@ -250,34 +230,24 @@ public void test_ConfigEOL_crlf() throws Exception {
@Test
public void test_ConfigEOL_native_windows() throws Exception {
- String origLineSeparator = System.getProperty("line.separator", "\n");
- System.setProperty("line.separator", "\r\n");
- try {
- // for EOL to work, the text attribute must be set
- setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
- collectRepositoryState();
- assertEquals("text", entryCRLF.attrs);
- checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
- } finally {
- System.setProperty("line.separator", origLineSeparator);
- }
+ mockSystemReader.setWindows();
+ // for EOL to work, the text attribute must be set
+ setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
+ collectRepositoryState();
+ assertEquals("text", entryCRLF.attrs);
+ checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
+ checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigEOL_native_xnix() throws Exception {
- String origLineSeparator = System.getProperty("line.separator", "\n");
- System.setProperty("line.separator", "\n");
- try {
- // for EOL to work, the text attribute must be set
- setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
- collectRepositoryState();
- assertEquals("text", entryCRLF.attrs);
- checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
- } finally {
- System.setProperty("line.separator", origLineSeparator);
- }
+ mockSystemReader.setUnix();
+ // for EOL to work, the text attribute must be set
+ setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
+ collectRepositoryState();
+ assertEquals("text", entryCRLF.attrs);
+ checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
+ checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
}
@Test
@@ -297,9 +267,10 @@ public void test_ConfigAutoCRLF_false_ConfigEOL_native() throws Exception {
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.NATIVE, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
- checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
+ String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
+ checkEntryContent(entryCRLF, expected, CONTENT_LF);
+ checkEntryContent(entryLF, expected, CONTENT_LF);
+ checkEntryContent(entryMixed, expected, CONTENT_LF);
}
@Test
@@ -524,9 +495,12 @@ public void test_GlobalEOL_lf_InfoEOL_unspec_RootEOL_crlf()
// info overrides all
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
- checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
- checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
+ // !eol means unspecified, so use the default of core.eol, which is
+ // native.
+ String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
+ checkEntryContent(entryCRLF, expected, CONTENT_LF);
+ checkEntryContent(entryLF, expected, CONTENT_LF);
+ checkEntryContent(entryMixed, expected, CONTENT_LF);
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java
index 36ba7ce..9ea64ef 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java
@@ -259,7 +259,8 @@ private RevCommit updateSubmoduleRevision() throws Exception {
// the commit that was created
try (SubmoduleWalk w = SubmoduleWalk.forIndex(git.getRepository())) {
assertTrue(w.next());
- try (Git g = new Git(w.getRepository())) {
+ try (Repository repository = w.getRepository();
+ Git g = new Git(repository)) {
g.fetch().setRemote(REMOTE).setRefSpecs(REFSPEC).call();
g.reset().setMode(ResetType.HARD).setRef(commit1.name()).call();
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index bc4e940..64475f5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -554,7 +554,7 @@ public void testMergeMessage() throws Exception {
git.merge().include(sideBranch)
.setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n",
+ assertEquals("Merge branch 'side'\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg());
}
@@ -1787,7 +1787,7 @@ public void testSquashMergeConflict() throws Exception {
+ dateFormatter.formatDate(third
.getAuthorIdent()) + "\n\n\tthird commit\n",
db.readSquashCommitMsg());
- assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg());
+ assertEquals("\n# Conflicts:\n#\tfile2\n", db.readMergeCommitMsg());
Status stat = git.status().call();
assertEquals(Sets.of("file2"), stat.getConflicting());
@@ -1881,6 +1881,7 @@ public void testFastForwardOnlyNotPossible() throws Exception {
@Test
public void testRecursiveMergeWithConflict() throws Exception {
try (TestRepository<Repository> db_t = new TestRepository<>(db)) {
+ db.incrementOpen();
BranchBuilder master = db_t.branch("master");
RevCommit m0 = master.commit()
.add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m0")
@@ -2012,7 +2013,7 @@ public void testMergeConflictWithMessageOption() throws Exception {
git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
.setMessage("user message").call();
- assertEquals("user message\n\nConflicts:\n\ta\n",
+ assertEquals("user message\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg());
}
}
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 9af77aa..6a84f0a 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
@@ -567,6 +567,7 @@ private void doTestPullWithRebase(Callable<PullResult> pullSetup,
public void setUp() throws Exception {
super.setUp();
dbTarget = createWorkRepository();
+ addRepoToClose(dbTarget);
source = new Git(db);
target = new Git(dbTarget);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
index cce04f4..e2d7923 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
@@ -323,6 +323,7 @@ public void setUp() throws Exception {
dbTarget = createWorkRepository();
source = new Git(db);
target = new Git(dbTarget);
+ addRepoToClose(dbTarget);
// put some file in the source repo
sourceFile = new File(db.getWorkTree(), "SomeFile.txt");
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 a786065..6f7aa63 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
@@ -10,7 +10,9 @@
package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -19,10 +21,13 @@
import java.net.URISyntaxException;
import java.util.Properties;
+import org.eclipse.jgit.api.errors.DetachedHeadException;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.hooks.PrePushHook;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
@@ -32,6 +37,7 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.PushConfig.PushDefault;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefLeaseSpec;
import org.eclipse.jgit.transport.RefSpec;
@@ -50,6 +56,7 @@ public void testPush() throws JGitInternalException, IOException,
// create other repository
Repository db2 = createWorkRepository();
+ addRepoToClose(db2);
final StoredConfig config2 = db2.getConfig();
// this tests that this config can be parsed properly
@@ -289,6 +296,770 @@ public void testPushWithoutPushRefSpec() throws Exception {
}
/**
+ * Check that pushing from a detached HEAD without refspec throws a
+ * DetachedHeadException.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultDetachedHead() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ final StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+ git.checkout().setName(commit.getName()).call();
+ String head = git.getRepository().getFullBranch();
+ assertTrue(ObjectId.isId(head));
+ assertEquals(commit.getName(), head);
+ assertThrows(DetachedHeadException.class,
+ () -> git.push().setRemote("test").call());
+ }
+ }
+
+ /**
+ * Check that push.default=nothing without refspec throws an
+ * InvalidRefNameException.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultNothing() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ final StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertThrows(InvalidRefNameException.class,
+ () -> git.push().setRemote("test")
+ .setPushDefault(PushDefault.NOTHING).call());
+ }
+ }
+
+ /**
+ * Check that push.default=matching without refspec pushes all matching
+ * branches.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultMatching() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ final StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ // push master and branchtopush
+ git.push().setRemote("test").setRefSpecs(
+ new RefSpec("refs/heads/master:refs/heads/master"),
+ new RefSpec(
+ "refs/heads/branchtopush:refs/heads/branchtopush"))
+ .call();
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ // Create two different commits on these two branches
+ writeTrashFile("b", "on branchtopush");
+ git.add().addFilepattern("b").call();
+ RevCommit bCommit = git.commit().setMessage("on branchtopush")
+ .call();
+ git.checkout().setName("master").call();
+ writeTrashFile("m", "on master");
+ git.add().addFilepattern("m").call();
+ RevCommit mCommit = git.commit().setMessage("on master").call();
+ // Now push with mode "matching": should push both branches.
+ Iterable<PushResult> result = git.push().setRemote("test")
+ .setPushDefault(PushDefault.MATCHING)
+ .call();
+ int n = 0;
+ for (PushResult r : result) {
+ n++;
+ assertEquals(1, n);
+ assertEquals(2, r.getRemoteUpdates().size());
+ for (RemoteRefUpdate update : r.getRemoteUpdates()) {
+ assertFalse(update.isMatching());
+ assertTrue(update.getSrcRef()
+ .equals("refs/heads/branchtopush")
+ || update.getSrcRef().equals("refs/heads/master"));
+ assertEquals(RemoteRefUpdate.Status.OK, update.getStatus());
+ }
+ }
+ assertEquals(bCommit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(mCommit.getId(),
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(bCommit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ assertEquals(null, git.getRepository()
+ .resolve("refs/remotes/origin/not-pushed"));
+ assertEquals(mCommit.getId(),
+ git.getRepository().resolve("refs/remotes/origin/master"));
+ }
+ }
+
+ /**
+ * Check that push.default=upstream without refspec pushes only the current
+ * branch to the configured upstream.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultUpstream() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/upstreambranch");
+ config.save();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/upstreambranch"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ git.push().setRemote("test").setPushDefault(PushDefault.UPSTREAM)
+ .call();
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/upstreambranch"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/upstreambranch"));
+ assertEquals(null, git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ }
+ }
+
+ /**
+ * Check that push.default=upstream without refspec throws an
+ * InvalidRefNameException if the current branch has no upstream.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultUpstreamNoTracking() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.save();
+
+ assertThrows(InvalidRefNameException.class,
+ () -> git.push().setRemote("test")
+ .setPushDefault(PushDefault.UPSTREAM).call());
+ }
+ }
+
+ /**
+ * Check that push.default=upstream without refspec throws an
+ * InvalidRefNameException if the push remote is not the same as the fetch
+ * remote.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultUpstreamTriangular() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ // Don't configure a remote; it'll default to "origin".
+ config.setString("branch", "branchtopush", "merge",
+ "upstreambranch");
+ config.save();
+
+ assertThrows(InvalidRefNameException.class,
+ () -> git.push().setRemote("test")
+ .setPushDefault(PushDefault.UPSTREAM).call());
+ }
+ }
+
+ /**
+ * Check that push.default=simple without refspec pushes only the current
+ * branch to the configured upstream name.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultSimple() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/branchtopush");
+ config.save();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ git.push().setRemote("test").setPushDefault(PushDefault.SIMPLE)
+ .call();
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ }
+ }
+
+ /**
+ * Check that push.default=simple without refspec pushes only the current
+ * branch to a branch with the same name in a triangular workflow.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultSimpleTriangular() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ // Don't set remote, it'll default to "origin". Configure a
+ // different branch name; should be ignored.
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/upstreambranch");
+ config.save();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/upstreambranch"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ git.push().setRemote("test").setPushDefault(PushDefault.SIMPLE)
+ .call();
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/upstreambranch"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ }
+ }
+
+ /**
+ * Check that push.default=simple without refspec throws an
+ * InvalidRefNameException if the current branch has no upstream.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultSimpleNoTracking() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.save();
+
+ assertThrows(InvalidRefNameException.class,
+ () -> git.push().setRemote("test")
+ .setPushDefault(PushDefault.SIMPLE).call());
+ }
+ }
+
+ /**
+ * Check that push.default=simple without refspec throws an
+ * InvalidRefNameException if the current branch has an upstream with a
+ * different name.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultSimpleDifferentTracking() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/upstreambranch");
+ config.save();
+
+ assertThrows(InvalidRefNameException.class,
+ () -> git.push().setRemote("test")
+ .setPushDefault(PushDefault.SIMPLE).call());
+ }
+ }
+
+ /**
+ * Check that if no PushDefault is set, the value is read from the git
+ * config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultFromConfig() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.setString("push", null, "default", "upstream");
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/upstreambranch");
+ config.save();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/upstreambranch"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ PushCommand cmd = git.push();
+ cmd.setRemote("test").setPushDefault(null).call();
+ assertEquals(PushDefault.UPSTREAM, cmd.getPushDefault());
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/upstreambranch"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/upstreambranch"));
+ assertEquals(null, git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ }
+ }
+
+ /**
+ * Check that if no PushDefault is set and none is set in the git config, it
+ * defaults to "simple".
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testPushDefaultFromConfigDefault() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/branchtopush");
+ config.save();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ PushCommand cmd = git.push();
+ cmd.setRemote("test").setPushDefault(null).call();
+ assertEquals(PushDefault.SIMPLE, cmd.getPushDefault());
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ }
+ }
+
+ /**
+ * Check that branch.<name>.pushRemote overrides anything else.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBranchPushRemote() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.setString("remote", null, "pushDefault", "test");
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "pushremote", "origin");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/branchtopush");
+ config.save();
+
+ assertThrows(InvalidRefNameException.class, () -> git.push()
+ .setPushDefault(PushDefault.UPSTREAM).call());
+ }
+ }
+
+ /**
+ * Check that remote.pushDefault overrides branch.<name>.remote
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRemotePushDefault() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.setString("remote", null, "pushDefault", "origin");
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/branchtopush");
+ config.save();
+
+ assertThrows(InvalidRefNameException.class, () -> git.push()
+ .setPushDefault(PushDefault.UPSTREAM).call());
+ }
+ }
+
+ /**
+ * Check that ultimately we fall back to "origin".
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testDefaultRemote() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "merge",
+ "refs/heads/branchtopush");
+ config.save();
+
+ PushCommand cmd = git.push().setPushDefault(PushDefault.UPSTREAM);
+ TransportException e = assertThrows(TransportException.class,
+ () -> cmd.call());
+ assertEquals(NoRemoteRepositoryException.class,
+ e.getCause().getClass());
+ assertEquals("origin", cmd.getRemote());
+ }
+ }
+
+ /**
+ * Check that a push without specifying a remote or mode or anything can
+ * succeed if the git config is correct.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testDefaultPush() throws Exception {
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(
+ git2.getRepository().getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
+
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
+
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
+
+ config = git.getRepository().getConfig();
+ config.setString("branch", "branchtopush", "remote", "test");
+ config.save();
+
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ // Should use remote "test", push.default=current
+ PushCommand cmd = git.push();
+ cmd.call();
+ assertEquals("test", cmd.getRemote());
+ assertEquals(PushDefault.CURRENT, cmd.getPushDefault());
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/not-pushed"));
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/master"));
+ assertEquals(commit.getId(), git.getRepository()
+ .resolve("refs/remotes/origin/branchtopush"));
+ }
+ }
+
+ /**
* Check that missing refs don't cause errors during push
*
* @throws Exception
@@ -297,6 +1068,7 @@ public void testPushWithoutPushRefSpec() throws Exception {
public void testPushAfterGC() throws Exception {
// create other repository
Repository db2 = createWorkRepository();
+ addRepoToClose(db2);
// setup the first repository
final StoredConfig config = db.getConfig();
@@ -360,6 +1132,7 @@ public void testPushWithLease() throws JGitInternalException, IOException,
// create other repository
Repository db2 = createWorkRepository();
+ addRepoToClose(db2);
// setup the first repository
final StoredConfig config = db.getConfig();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
index 8623902..c64ff0b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -2927,8 +2927,8 @@ public String modifyCommitMessage(String commit) {
}
}
- @Test
- public void testRebaseInteractiveFixupWithBlankLines() throws Exception {
+ private void simpleFixup(String firstMessage, String secondMessage)
+ throws Exception {
// create file1 on master
writeTrashFile(FILE1, FILE1);
git.add().addFilepattern(FILE1).call();
@@ -2938,13 +2938,13 @@ public void testRebaseInteractiveFixupWithBlankLines() throws Exception {
// create file2 on master
writeTrashFile("file2", "file2");
git.add().addFilepattern("file2").call();
- git.commit().setMessage("Add file2").call();
+ git.commit().setMessage(firstMessage).call();
assertTrue(new File(db.getWorkTree(), "file2").exists());
// update FILE1 on master
writeTrashFile(FILE1, "blah");
git.add().addFilepattern(FILE1).call();
- git.commit().setMessage("updated file1 on master\n\nsome text").call();
+ git.commit().setMessage(secondMessage).call();
git.rebase().setUpstream("HEAD~2")
.runInteractively(new InteractiveHandler() {
@@ -2968,9 +2968,31 @@ public String modifyCommitMessage(String commit) {
try (RevWalk walk = new RevWalk(db)) {
ObjectId headId = db.resolve(Constants.HEAD);
RevCommit headCommit = walk.parseCommit(headId);
- assertEquals("Add file2",
- headCommit.getFullMessage());
+ assertEquals(firstMessage, headCommit.getFullMessage());
}
+
+ }
+
+ @Test
+ public void testRebaseInteractiveFixupWithBlankLines() throws Exception {
+ simpleFixup("Add file2", "updated file1 on master\n\nsome text");
+ }
+
+ @Test
+ public void testRebaseInteractiveFixupWithBlankLines2() throws Exception {
+ simpleFixup("Add file2\n\nBody\n",
+ "updated file1 on master\n\nsome text");
+ }
+
+ @Test
+ public void testRebaseInteractiveFixupWithHash() throws Exception {
+ simpleFixup("#Add file2", "updated file1 on master");
+ }
+
+ @Test
+ public void testRebaseInteractiveFixupWithHash2() throws Exception {
+ simpleFixup("#Add file2\n\nHeader has hash\n",
+ "#updated file1 on master");
}
@Test(expected = InvalidRebaseStepException.class)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
index cfa8486..1c7b8d1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
@@ -9,6 +9,7 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -166,7 +167,9 @@ public void testRevertMultipleWithFail() throws IOException,
checkFile(new File(db.getWorkTree(), "a"), "first\n"
+ "<<<<<<< master\n" + "second\n" + "third\n" + "=======\n"
- + ">>>>>>> " + secondCommit.getId().abbreviate(7).name()
+ + ">>>>>>> "
+ + secondCommit.getId()
+ .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name()
+ " add second\n");
Iterator<RevCommit> history = git.log().call().iterator();
RevCommit revertCommit = history.next();
@@ -232,7 +235,7 @@ public void testRevertConflictResolution() throws Exception {
assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
assertEquals("Revert \"" + sideCommit.getShortMessage()
+ "\"\n\nThis reverts commit " + sideCommit.getId().getName()
- + ".\n\nConflicts:\n\ta\n",
+ + ".\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg());
assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD)
.exists());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
index 5311edb..19281f6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
@@ -21,8 +21,10 @@
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.util.FS;
import org.junit.Test;
@@ -181,4 +183,31 @@ public void testFolderPrefix() throws Exception {
}
}
+ @Test
+ public void testNestedCommittedGitRepoAndPathFilter() throws Exception {
+ commitFile("file.txt", "file", "master");
+ try (Repository inner = new FileRepositoryBuilder()
+ .setWorkTree(new File(db.getWorkTree(), "subgit")).build()) {
+ inner.create();
+ writeTrashFile("subgit/sub.txt", "sub");
+ try (Git outerGit = new Git(db); Git innerGit = new Git(inner)) {
+ innerGit.add().addFilepattern("sub.txt").call();
+ innerGit.commit().setMessage("Inner commit").call();
+ outerGit.add().addFilepattern("subgit").call();
+ outerGit.commit().setMessage("Outer commit").call();
+ assertTrue(innerGit.status().call().isClean());
+ assertTrue(outerGit.status().call().isClean());
+ writeTrashFile("subgit/sub.txt", "sub2");
+ assertFalse(innerGit.status().call().isClean());
+ assertFalse(outerGit.status().call().isClean());
+ assertTrue(
+ outerGit.status().addPath("file.txt").call().isClean());
+ assertTrue(outerGit.status().addPath("doesntexist").call()
+ .isClean());
+ assertFalse(
+ outerGit.status().addPath("subgit").call().isClean());
+ }
+ }
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java
new file mode 100644
index 0000000..c3b9387
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021, Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gitrepo;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jgit.gitrepo.BareSuperprojectWriter.BareWriterConfig;
+import org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Test;
+
+public class BareSuperprojectWriterTest extends RepositoryTestCase {
+
+ private static final String SHA1_A = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Test
+ public void write_setGitModulesContents() throws Exception {
+ try (Repository bareRepo = createBareRepository()) {
+ RepoProject repoProject = new RepoProject("subprojectX", "path/to",
+ "refs/heads/branch-x", "remote", "");
+ repoProject.setUrl("http://example.com/a");
+
+ RemoteReader mockRemoteReader = mock(RemoteReader.class);
+ when(mockRemoteReader.sha1("http://example.com/a",
+ "refs/heads/branch-x"))
+ .thenReturn(ObjectId.fromString(SHA1_A));
+
+ BareSuperprojectWriter w = new BareSuperprojectWriter(bareRepo,
+ null, "refs/heads/master", author, mockRemoteReader,
+ BareWriterConfig.getDefault(), List.of());
+
+ RevCommit commit = w.write(Arrays.asList(repoProject));
+
+ String contents = readContents(bareRepo, commit, ".gitmodules");
+ List<String> contentLines = Arrays
+ .asList(contents.split("\n"));
+ assertThat(contentLines.get(0),
+ is("[submodule \"subprojectX\"]"));
+ assertThat(contentLines.subList(1, contentLines.size()),
+ containsInAnyOrder(is("\tbranch = refs/heads/branch-x"),
+ is("\tpath = path/to"),
+ is("\turl = http://example.com/a")));
+ }
+ }
+
+ @Test
+ public void write_setExtraContents() throws Exception {
+ try (Repository bareRepo = createBareRepository()) {
+ RepoProject repoProject = new RepoProject("subprojectX", "path/to",
+ "refs/heads/branch-x", "remote", "");
+ repoProject.setUrl("http://example.com/a");
+
+ RemoteReader mockRemoteReader = mock(RemoteReader.class);
+ when(mockRemoteReader.sha1("http://example.com/a",
+ "refs/heads/branch-x"))
+ .thenReturn(ObjectId.fromString(SHA1_A));
+
+ BareSuperprojectWriter w = new BareSuperprojectWriter(bareRepo,
+ null, "refs/heads/master", author, mockRemoteReader,
+ BareWriterConfig.getDefault(),
+ List.of(new BareSuperprojectWriter.ExtraContent("x",
+ "extra-content")));
+
+ RevCommit commit = w.write(Arrays.asList(repoProject));
+
+ String contents = readContents(bareRepo, commit, "x");
+ assertThat(contents, is("extra-content"));
+ }
+ }
+
+ private String readContents(Repository repo, RevCommit commit,
+ String path) throws Exception {
+ String idStr = commit.getId().name() + ":" + path;
+ ObjectId modId = repo.resolve(idStr);
+ try (ObjectReader reader = repo.newObjectReader()) {
+ return new String(
+ reader.open(modId).getCachedBytes(Integer.MAX_VALUE),
+ StandardCharsets.UTF_8);
+
+ }
+ }
+}
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 509adc2..3e6d13a 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
@@ -15,6 +15,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
@@ -546,24 +547,29 @@ public void testRepoManifestCopyFile() throws Exception {
// The original file should exist
File hello = new File(localDb.getWorkTree(), "foo/hello.txt");
assertTrue("The original file should exist", hello.exists());
- assertFalse("The original file should not be executable",
- hello.canExecute());
+ if (FS.DETECTED.supportsExecute()) {
+ assertFalse("The original file should not be executable",
+ FS.DETECTED.canExecute(hello));
+ }
assertContents(hello.toPath(), "master world");
// The dest file should also exist
hello = new File(localDb.getWorkTree(), "Hello");
assertTrue("The destination file should exist", hello.exists());
- assertFalse("The destination file should not be executable",
- hello.canExecute());
+ if (FS.DETECTED.supportsExecute()) {
+ assertFalse("The destination file should not be executable",
+ FS.DETECTED.canExecute(hello));
+ }
assertContents(hello.toPath(), "master world");
}
@Test
public void testRepoManifestCopyFile_executable() throws Exception {
+ assumeTrue(FS.DETECTED.supportsExecute());
try (Git git = new Git(defaultDb)) {
git.checkout().setName("master").call();
File f = JGitTestUtil.writeTrashFile(defaultDb, "hello.sh",
"content of the executable file");
- f.setExecutable(true);
+ FS.DETECTED.setExecute(f, true);
git.add().addFilepattern("hello.sh").call();
git.commit().setMessage("Add binary file").call();
}
@@ -588,7 +594,8 @@ public void testRepoManifestCopyFile_executable() throws Exception {
// The original file should exist and be an executable
File hello = new File(localDb.getWorkTree(), "foo/hello.sh");
assertTrue("The original file should exist", hello.exists());
- assertTrue("The original file must be executable", hello.canExecute());
+ assertTrue("The original file must be executable",
+ FS.DETECTED.canExecute(hello));
try (BufferedReader reader = Files.newBufferedReader(hello.toPath(),
UTF_8)) {
String content = reader.readLine();
@@ -600,7 +607,7 @@ public void testRepoManifestCopyFile_executable() throws Exception {
hello = new File(localDb.getWorkTree(), "copy-hello.sh");
assertTrue("The destination file should exist", hello.exists());
assertTrue("The destination file must be executable",
- hello.canExecute());
+ FS.DETECTED.canExecute(hello));
try (BufferedReader reader = Files.newBufferedReader(hello.toPath(),
UTF_8)) {
String content = reader.readLine();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
new file mode 100644
index 0000000..c9ebec7
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020-2021, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.diffmergetool;
+
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.junit.Test;
+
+/**
+ * Testing external diff tools.
+ */
+public class ExternalDiffToolTest extends ExternalToolTestCase {
+
+ @Test
+ public void testToolNames() {
+ DiffTools manager = new DiffTools(db);
+ Set<String> actualToolNames = manager.getToolNames();
+ Set<String> expectedToolNames = Collections.emptySet();
+ assertEquals("Incorrect set of external diff tool names",
+ expectedToolNames, actualToolNames);
+ }
+
+ @Test
+ public void testAllTools() {
+ DiffTools manager = new DiffTools(db);
+ Set<String> actualToolNames = manager.getAvailableTools().keySet();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
+ for (CommandLineDiffTool defaultTool : defaultTools) {
+ String toolName = defaultTool.name();
+ expectedToolNames.add(toolName);
+ }
+ assertEquals("Incorrect set of external diff tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testOverridePredefinedToolPath() {
+ String toolName = CommandLineDiffTool.guiffy.name();
+ String customToolPath = "/usr/bin/echo";
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ "echo");
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_PATH,
+ customToolPath);
+
+ DiffTools manager = new DiffTools(db);
+ Map<String, ExternalDiffTool> tools = manager.getUserDefinedTools();
+ ExternalDiffTool diffTool = tools.get(toolName);
+ assertNotNull("Expected tool \"" + toolName + "\" to be user defined",
+ diffTool);
+
+ String toolPath = diffTool.getPath();
+ assertEquals("Expected external diff tool to have an overriden path",
+ customToolPath, toolPath);
+ }
+
+ @Test
+ public void testUserDefinedTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolname = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
+ CONFIG_KEY_CMD, "echo");
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
+ CONFIG_KEY_PATH, "/usr/bin/echo");
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
+ CONFIG_KEY_PROMPT, "--no-prompt");
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
+ CONFIG_KEY_GUITOOL, "--no-gui");
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
+ CONFIG_KEY_TRUST_EXIT_CODE, "--no-trust-exit-code");
+ DiffTools manager = new DiffTools(db);
+ Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolname);
+ assertEquals("Incorrect set of external diff tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testNotAvailableTools() {
+ DiffTools manager = new DiffTools(db);
+ Set<String> actualToolNames = manager.getNotAvailableTools().keySet();
+ Set<String> expectedToolNames = Collections.emptySet();
+ assertEquals("Incorrect set of not available external diff tools",
+ expectedToolNames, actualToolNames);
+ }
+
+ @Test
+ public void testCompare() {
+ DiffTools manager = new DiffTools(db);
+
+ String newPath = "";
+ String oldPath = "";
+ String newId = "";
+ String oldId = "";
+ String toolName = "";
+ BooleanTriState prompt = BooleanTriState.UNSET;
+ BooleanTriState gui = BooleanTriState.UNSET;
+ BooleanTriState trustExitCode = BooleanTriState.UNSET;
+
+ int expectedCompareResult = 0;
+ int compareResult = manager.compare(newPath, oldPath, newId, oldId,
+ toolName, prompt, gui, trustExitCode);
+ assertEquals("Incorrect compare result for external diff tool",
+ expectedCompareResult, compareResult);
+ }
+
+ @Test
+ public void testDefaultTool() throws Exception {
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString("diff", subsection, "tool", "customTool");
+
+ DiffTools manager = new DiffTools(db);
+ BooleanTriState gui = BooleanTriState.UNSET;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured difftool to be the default external diff tool",
+ "my_default_toolname", defaultToolName);
+
+ gui = BooleanTriState.TRUE;
+ String defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured difftool to be the default external diff tool",
+ "my_gui_tool", defaultGuiToolName);
+
+ config.setString("diff", subsection, "guitool", "customGuiTool");
+ manager = new DiffTools(db);
+ defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured difftool to be the default external diff guitool",
+ "my_gui_tool", defaultGuiToolName);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
new file mode 100644
index 0000000..0cc1297
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020-2021, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.diffmergetool;
+
+import java.io.File;
+import java.nio.file.Files;
+
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS_POSIX;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+
+/**
+ * Base test case for external merge and diff tool tests.
+ */
+public abstract class ExternalToolTestCase extends RepositoryTestCase {
+
+ protected static final String DEFAULT_CONTENT = "line1";
+
+ protected File localFile;
+
+ protected File remoteFile;
+
+ protected File mergedFile;
+
+ protected File baseFile;
+
+ protected File commandResult;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ localFile = writeTrashFile("localFile.txt", DEFAULT_CONTENT + "\n");
+ localFile.deleteOnExit();
+ remoteFile = writeTrashFile("remoteFile.txt", DEFAULT_CONTENT + "\n");
+ remoteFile.deleteOnExit();
+ mergedFile = writeTrashFile("mergedFile.txt", "");
+ mergedFile.deleteOnExit();
+ baseFile = writeTrashFile("baseFile.txt", "");
+ baseFile.deleteOnExit();
+ commandResult = writeTrashFile("commandResult.txt", "");
+ commandResult.deleteOnExit();
+ }
+
+ @After
+ @Override
+ public void tearDown() throws Exception {
+ Files.delete(localFile.toPath());
+ Files.delete(remoteFile.toPath());
+ Files.delete(mergedFile.toPath());
+ Files.delete(baseFile.toPath());
+ Files.delete(commandResult.toPath());
+
+ super.tearDown();
+ }
+
+
+ protected static void assumePosixPlatform() {
+ Assume.assumeTrue(
+ "This test can run only in Linux tests",
+ FS.DETECTED instanceof FS_POSIX);
+ }
+}
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
index 4f13140..ab588cb 100644
--- 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
@@ -15,16 +15,19 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.LongStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.IndexEventConsumer;
import org.eclipse.jgit.internal.storage.pack.PackExt;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.TestRng;
@@ -154,6 +157,119 @@ public void hasCacheHotMap() throws Exception {
@SuppressWarnings("resource")
@Test
+ public void hasIndexEventConsumerOnlyLoaded() throws Exception {
+ AtomicInteger loaded = new AtomicInteger();
+ IndexEventConsumer indexEventConsumer = new IndexEventConsumer() {
+ @Override
+ public void acceptRequestedEvent(int packExtPos, boolean cacheHit,
+ long loadMicros, long bytes,
+ Duration lastEvictionDuration) {
+ assertEquals(PackExt.INDEX.getPosition(), packExtPos);
+ assertTrue(cacheHit);
+ assertTrue(lastEvictionDuration.isZero());
+ loaded.incrementAndGet();
+ }
+ };
+
+ DfsBlockCache.reconfigure(new DfsBlockCacheConfig().setBlockSize(512)
+ .setBlockLimit(512 * 4)
+ .setIndexEventConsumer(indexEventConsumer));
+ cache = DfsBlockCache.getInstance();
+
+ 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();
+ }
+
+ try (ObjectReader rdr = r1.newObjectReader()) {
+ byte[] actual = rdr.open(id, OBJ_BLOB).getBytes();
+ assertTrue(Arrays.equals(content, actual));
+ }
+ // All cache entries are hot and cache is at capacity.
+ assertTrue(LongStream.of(cache.getHitCount()).sum() > 0);
+ assertEquals(99, cache.getFillPercentage());
+
+ InMemoryRepository r2 = new InMemoryRepository(repo);
+ content = rng.nextBytes(424242);
+ try (ObjectInserter ins = r2.newObjectInserter()) {
+ ins.insert(OBJ_BLOB, content);
+ ins.flush();
+ }
+ assertTrue(cache.getEvictions()[PackExt.PACK.getPosition()] > 0);
+ assertEquals(1, cache.getEvictions()[PackExt.INDEX.getPosition()]);
+ assertEquals(1, loaded.get());
+ }
+
+ @SuppressWarnings("resource")
+ @Test
+ public void hasIndexEventConsumerLoadedAndEvicted() throws Exception {
+ AtomicInteger loaded = new AtomicInteger();
+ AtomicInteger evicted = new AtomicInteger();
+ IndexEventConsumer indexEventConsumer = new IndexEventConsumer() {
+ @Override
+ public void acceptRequestedEvent(int packExtPos, boolean cacheHit,
+ long loadMicros, long bytes,
+ Duration lastEvictionDuration) {
+ assertEquals(PackExt.INDEX.getPosition(), packExtPos);
+ assertTrue(cacheHit);
+ assertTrue(lastEvictionDuration.isZero());
+ loaded.incrementAndGet();
+ }
+
+ @Override
+ public void acceptEvictedEvent(int packExtPos, long bytes,
+ int totalCacheHitCount, Duration lastEvictionDuration) {
+ assertEquals(PackExt.INDEX.getPosition(), packExtPos);
+ assertTrue(totalCacheHitCount > 0);
+ assertTrue(lastEvictionDuration.isZero());
+ evicted.incrementAndGet();
+ }
+
+ @Override
+ public boolean shouldReportEvictedEvent() {
+ return true;
+ }
+ };
+
+ DfsBlockCache.reconfigure(new DfsBlockCacheConfig().setBlockSize(512)
+ .setBlockLimit(512 * 4)
+ .setIndexEventConsumer(indexEventConsumer));
+ cache = DfsBlockCache.getInstance();
+
+ 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();
+ }
+
+ try (ObjectReader rdr = r1.newObjectReader()) {
+ byte[] actual = rdr.open(id, OBJ_BLOB).getBytes();
+ assertTrue(Arrays.equals(content, actual));
+ }
+ // All cache entries are hot and cache is at capacity.
+ assertTrue(LongStream.of(cache.getHitCount()).sum() > 0);
+ assertEquals(99, cache.getFillPercentage());
+
+ InMemoryRepository r2 = new InMemoryRepository(repo);
+ content = rng.nextBytes(424242);
+ try (ObjectInserter ins = r2.newObjectInserter()) {
+ ins.insert(OBJ_BLOB, content);
+ ins.flush();
+ }
+ assertTrue(cache.getEvictions()[PackExt.PACK.getPosition()] > 0);
+ assertEquals(1, cache.getEvictions()[PackExt.INDEX.getPosition()]);
+ assertEquals(1, loaded.get());
+ assertEquals(1, evicted.get());
+ }
+
+ @Test
public void noConcurrencySerializedReads_oneRepo() throws Exception {
InMemoryRepository r1 = createRepoWithBitmap("test");
// Reset cache with concurrency Level at 1 i.e. no concurrency.
@@ -267,7 +383,6 @@ public void lowConcurrencyParallelReads_twoReposAndIndex()
assertEquals(2, cache.getMissCount()[0]);
}
- @SuppressWarnings("resource")
@Test
public void highConcurrencyParallelReads_oneRepo() throws Exception {
InMemoryRepository r1 = createRepoWithBitmap("test");
@@ -290,6 +405,30 @@ public void highConcurrencyParallelReads_oneRepo() throws Exception {
assertEquals(1, cache.getMissCount()[0]);
}
+ @Test
+ public void highConcurrencyParallelReads_oneRepoParallelReverseIndex()
+ throws Exception {
+ InMemoryRepository r1 = createRepoWithBitmap("test");
+ resetCache();
+
+ DfsReader reader = (DfsReader) r1.newObjectReader();
+ reader.getOptions().setLoadRevIndexInParallel(true);
+ for (DfsPackFile pack : r1.getObjectDatabase().getPacks()) {
+ // Only load non-garbage pack with bitmap.
+ if (pack.isGarbage()) {
+ continue;
+ }
+ asyncRun(() -> pack.getBitmapIndex(reader));
+ asyncRun(() -> pack.getPackIndex(reader));
+ asyncRun(() -> pack.getBitmapIndex(reader));
+ }
+ waitForExecutorPoolTermination();
+
+ assertEquals(1, cache.getMissCount()[PackExt.BITMAP_INDEX.ordinal()]);
+ assertEquals(1, cache.getMissCount()[PackExt.INDEX.ordinal()]);
+ assertEquals(1, cache.getMissCount()[0]);
+ }
+
private void resetCache() {
resetCache(32);
}
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
index 6357a0b..daf4382 100644
--- 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
@@ -42,6 +42,8 @@
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.RefsChangedListener;
@@ -127,6 +129,7 @@ public void setUp() throws Exception {
}
diskRepo = fileRepo;
+ addRepoToClose(diskRepo);
setLogAllRefUpdates(true);
if (!useReftable) {
@@ -1190,7 +1193,8 @@ private void assertRefs(Object... args) throws IOException {
}
Map<String, Ref> refs = diskRepo.getRefDatabase()
- .getRefs(RefDatabase.ALL);
+ .getRefsByPrefix(RefDatabase.ALL).stream()
+ .collect(Collectors.toMap(Ref::getName, Function.identity()));
Ref actualHead = refs.remove(Constants.HEAD);
if (actualHead != null) {
String actualLeafName = actualHead.getLeaf().getName();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java
index 6c74f00..6c79927 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java
@@ -14,6 +14,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import java.io.File;
import java.io.FileNotFoundException;
@@ -32,10 +33,12 @@
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.SystemReader;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+
public class FileReftableStackTest {
private static Ref newRef(String name, ObjectId id) {
@@ -115,9 +118,12 @@ public void testCompaction1024() throws Exception {
testCompaction(1024);
}
- @SuppressWarnings({ "resource", "unused" })
+ @SuppressWarnings("resource")
@Test
public void missingReftable() throws Exception {
+ // Can't delete in-use files on Windows.
+ assumeFalse(SystemReader.getInstance().isWindows());
+
try (FileReftableStack stack = new FileReftableStack(
new File(reftableDir, "refs"), reftableDir, null,
() -> new Config())) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
index bfb233f..48f6e06 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
@@ -42,6 +42,7 @@ public void setUp() throws Exception {
@Override
@After
public void tearDown() throws Exception {
+ tr.close();
super.tearDown();
}
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 1ff2264..3fe8f52 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
@@ -722,6 +722,7 @@ public void testPartialPackFilesScanWhenDoingSearchForReuseTimeoutCheck()
*/
private FileRepository setUpRepoWithMultiplePackfiles() throws Exception {
FileRepository fileRepository = createWorkRepository();
+ addRepoToClose(fileRepository);
try (Git git = new Git(fileRepository)) {
// Creates 2 objects (C1 = commit, T1 = tree)
git.commit().setMessage("First commit").call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/io/CancellableDigestOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/io/CancellableDigestOutputStreamTest.java
new file mode 100644
index 0000000..09a7c0b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/io/CancellableDigestOutputStreamTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022, Tencent.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.storage.io;
+
+import static org.eclipse.jgit.internal.storage.io.CancellableDigestOutputStream.BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InterruptedIOException;
+
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.util.io.NullOutputStream;
+import org.junit.Test;
+
+public class CancellableDigestOutputStreamTest {
+ private static class CancelledTestMonitor implements ProgressMonitor {
+
+ private boolean cancelled = false;
+
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @Override
+ public void start(int totalTasks) {
+ // not implemented
+ }
+
+ @Override
+ public void beginTask(String title, int totalWork) {
+ // not implemented
+ }
+
+ @Override
+ public void update(int completed) {
+ // not implemented
+ }
+
+ @Override
+ public void endTask() {
+ // not implemented
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+ }
+
+ @Test
+ public void testCancelInProcess() throws Exception {
+ CancelledTestMonitor m = new CancelledTestMonitor();
+ try (CancellableDigestOutputStream out = new CancellableDigestOutputStream(
+ m, NullOutputStream.INSTANCE)) {
+ byte[] KB = new byte[1024];
+ int triggerCancelWriteCnt = BYTES_TO_WRITE_BEFORE_CANCEL_CHECK
+ / KB.length;
+ for (int i = 0; i < triggerCancelWriteCnt + 1; i++) {
+ out.write(KB);
+ }
+ assertTrue(out.length() > BYTES_TO_WRITE_BEFORE_CANCEL_CHECK);
+ m.setCancelled(true);
+
+ for (int i = 0; i < triggerCancelWriteCnt - 1; i++) {
+ out.write(KB);
+ }
+
+ long lastLength = out.length();
+ assertThrows(InterruptedIOException.class, () -> {
+ out.write(1);
+ });
+ assertEquals(lastLength, out.length());
+
+ assertThrows(InterruptedIOException.class, () -> {
+ out.write(new byte[1]);
+ });
+ assertEquals(lastLength, out.length());
+ }
+ }
+
+ @Test
+ public void testTriggerCheckAfterSingleBytes() throws Exception {
+ CancelledTestMonitor m = new CancelledTestMonitor();
+ try (CancellableDigestOutputStream out = new CancellableDigestOutputStream(
+ m, NullOutputStream.INSTANCE)) {
+
+ byte[] bytes = new byte[BYTES_TO_WRITE_BEFORE_CANCEL_CHECK + 1];
+ m.setCancelled(true);
+
+ assertThrows(InterruptedIOException.class, () -> {
+ out.write(bytes);
+ });
+ assertEquals(BYTES_TO_WRITE_BEFORE_CANCEL_CHECK, out.length());
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFileTest.java
index 11741b4..d065280 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFileTest.java
@@ -369,20 +369,21 @@ public void testHostCaseInsensitive() throws Exception {
@Test
public void testListValueSingle() throws Exception {
- config("Host orcz\nUserKnownHostsFile /foo/bar\n");
+ config("Host orcz\nUserKnownHostsFile ~/foo/bar\n");
final HostConfig c = lookup("orcz");
assertNotNull(c);
- assertEquals("/foo/bar", c.getValue("UserKnownHostsFile"));
+ assertEquals(new File(home, "foo/bar").getPath(),
+ c.getValue("UserKnownHostsFile"));
}
@Test
public void testListValueMultiple() throws Exception {
// Tilde expansion occurs within the parser
- config("Host orcz\nUserKnownHostsFile \"~/foo/ba z\" /foo/bar \n");
+ config("Host orcz\nUserKnownHostsFile \"~/foo/ba z\" ~/foo/bar \n");
final HostConfig c = lookup("orcz");
assertNotNull(c);
assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
- "/foo/bar" },
+ new File(home, "foo/bar").getPath() },
c.getValues("UserKnownHostsFile").toArray());
}
@@ -403,22 +404,23 @@ public void testRepeatedLookupsWithModification() throws Exception {
@Test
public void testIdentityFile() throws Exception {
- config("Host orcz\nIdentityFile \"~/foo/ba z\"\nIdentityFile /foo/bar");
+ config("Host orcz\nIdentityFile \"~/foo/ba z\"\nIdentityFile ~/foo/bar");
final HostConfig h = lookup("orcz");
assertNotNull(h);
// Does tilde replacement
assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
- "/foo/bar" },
+ new File(home, "foo/bar").getPath() },
h.getValues(SshConstants.IDENTITY_FILE).toArray());
}
@Test
public void testMultiIdentityFile() throws Exception {
- config("IdentityFile \"~/foo/ba z\"\nHost orcz\nIdentityFile /foo/bar\nHOST *\nIdentityFile /foo/baz");
+ config("IdentityFile \"~/foo/ba z\"\nHost orcz\nIdentityFile ~/foo/bar\nHOST *\nIdentityFile ~/foo/baz");
final HostConfig h = lookup("orcz");
assertNotNull(h);
assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(),
- "/foo/bar", "/foo/baz" },
+ new File(home, "foo/bar").getPath(),
+ new File(home, "foo/baz").getPath() },
h.getValues(SshConstants.IDENTITY_FILE).toArray());
}
@@ -434,23 +436,23 @@ public void testNegatedPattern() throws Exception {
@Test
public void testPattern() throws Exception {
- config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz");
+ config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile ~/foo/baz");
final HostConfig h = lookup("repo.or.cz");
assertNotNull(h);
assertIdentity(new File(home, "foo/bar"), h);
assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(),
- "/foo/baz" },
+ new File(home, "foo/baz").getPath() },
h.getValues(SshConstants.IDENTITY_FILE).toArray());
}
@Test
public void testMultiHost() throws Exception {
- config("Host orcz *.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz");
+ config("Host orcz *.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile ~/foo/baz");
final HostConfig h1 = lookup("repo.or.cz");
assertNotNull(h1);
assertIdentity(new File(home, "foo/bar"), h1);
assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(),
- "/foo/baz" },
+ new File(home, "foo/baz").getPath() },
h1.getValues(SshConstants.IDENTITY_FILE).toArray());
final HostConfig h2 = lookup("orcz");
assertNotNull(h2);
@@ -547,18 +549,36 @@ public void testEolComments() throws Exception {
@Test
public void testEnVarSubstitution() throws Exception {
- config("Host orcz\nIdentityFile /tmp/${TST_VAR}\n"
- + "CertificateFile /tmp/${}/foo\nUser ${TST_VAR}\nIdentityAgent /tmp/${TST_VAR/bar");
+ config("Host orcz\nIdentityFile ~/tmp/${TST_VAR}\n"
+ + "CertificateFile ~/tmp/${}/foo\nUser ${TST_VAR}\nIdentityAgent ~/tmp/${TST_VAR/bar");
HostConfig h = lookup("orcz");
assertNotNull(h);
- assertEquals("/tmp/TEST",
+ File tmp = new File(home, "tmp");
+ assertEquals(new File(tmp, "TEST").getPath(),
h.getValue(SshConstants.IDENTITY_FILE));
// No variable name
- assertEquals("/tmp/${}/foo", h.getValue(SshConstants.CERTIFICATE_FILE));
+ assertEquals(new File(new File(tmp, "${}"), "foo").getPath(),
+ h.getValue(SshConstants.CERTIFICATE_FILE));
// User doesn't get env var substitution:
assertUser("${TST_VAR}", h);
// Unterminated:
- assertEquals("/tmp/${TST_VAR/bar",
+ assertEquals(new File(new File(tmp, "${TST_VAR"), "bar").getPath(),
+ h.getValue(SshConstants.IDENTITY_AGENT));
+ }
+
+ @Test
+ public void testIdentityAgentNone() throws Exception {
+ config("Host orcz\nIdentityAgent none\n");
+ HostConfig h = lookup("orcz");
+ assertEquals(SshConstants.NONE,
+ h.getValue(SshConstants.IDENTITY_AGENT));
+ }
+
+ @Test
+ public void testIdentityAgentSshAuthSock() throws Exception {
+ config("Host orcz\nIdentityAgent SSH_AUTH_SOCK\n");
+ HostConfig h = lookup("orcz");
+ assertEquals(SshConstants.ENV_SSH_AUTH_SOCKET,
h.getValue(SshConstants.IDENTITY_AGENT));
}
@@ -607,13 +627,16 @@ public void testNoMatch() throws Exception {
@Test
public void testMultipleMatch() throws Exception {
- config("Host foo.bar\nPort 29418\nIdentityFile /foo\n\n"
- + "Host *.bar\nPort 22\nIdentityFile /bar\n"
- + "Host foo.bar\nPort 47\nIdentityFile /baz\n");
+ config("Host foo.bar\nPort 29418\nIdentityFile ~/foo\n\n"
+ + "Host *.bar\nPort 22\nIdentityFile ~/bar\n"
+ + "Host foo.bar\nPort 47\nIdentityFile ~/baz\n");
HostConfig h = lookup("foo.bar");
assertNotNull(h);
assertPort(29418, h);
- assertArrayEquals(new Object[] { "/foo", "/bar", "/baz" },
+ assertArrayEquals(
+ new Object[] { new File(home, "foo").getPath(),
+ new File(home, "bar").getPath(),
+ new File(home, "baz").getPath() },
h.getValues(SshConstants.IDENTITY_FILE).toArray());
}
@@ -633,4 +656,61 @@ public void testWhitespace() throws Exception {
assertNotNull(h);
assertPort(22, h);
}
+
+ @Test
+ public void testTimeSpec() throws Exception {
+ assertEquals(-1, OpenSshConfigFile.timeSpec(null));
+ assertEquals(-1, OpenSshConfigFile.timeSpec(""));
+ assertEquals(-1, OpenSshConfigFile.timeSpec(" "));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("s"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec(" s"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec(" +s"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec(" -s"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("1ms"));
+ assertEquals(600, OpenSshConfigFile.timeSpec("600"));
+ assertEquals(600, OpenSshConfigFile.timeSpec("600s"));
+ assertEquals(600, OpenSshConfigFile.timeSpec(" 600s"));
+ assertEquals(600, OpenSshConfigFile.timeSpec(" 600s "));
+ assertEquals(600, OpenSshConfigFile.timeSpec("\t600s"));
+ assertEquals(600, OpenSshConfigFile.timeSpec(" \t600 "));
+ assertEquals(-1, OpenSshConfigFile.timeSpec(" 600 s "));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("600 s"));
+ assertEquals(600, OpenSshConfigFile.timeSpec("10m"));
+ assertEquals(5400, OpenSshConfigFile.timeSpec("1h30m"));
+ assertEquals(5400, OpenSshConfigFile.timeSpec("1h 30m"));
+ assertEquals(5400, OpenSshConfigFile.timeSpec("1h \t30m"));
+ assertEquals(5400, OpenSshConfigFile.timeSpec("1h+30m"));
+ assertEquals(5400, OpenSshConfigFile.timeSpec("1h +30m"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("1h + 30m"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("1h -30m"));
+ assertEquals(3630, OpenSshConfigFile.timeSpec("1h30s"));
+ assertEquals(5400, OpenSshConfigFile.timeSpec("30m 1h"));
+ assertEquals(3600, OpenSshConfigFile.timeSpec("30m 30m"));
+ assertEquals(60, OpenSshConfigFile.timeSpec("30 30"));
+ assertEquals(0, OpenSshConfigFile.timeSpec("0"));
+ assertEquals(1, OpenSshConfigFile.timeSpec("1"));
+ assertEquals(1, OpenSshConfigFile.timeSpec("1S"));
+ assertEquals(1, OpenSshConfigFile.timeSpec("1s"));
+ assertEquals(60, OpenSshConfigFile.timeSpec("1M"));
+ assertEquals(60, OpenSshConfigFile.timeSpec("1m"));
+ assertEquals(3600, OpenSshConfigFile.timeSpec("1H"));
+ assertEquals(3600, OpenSshConfigFile.timeSpec("1h"));
+ assertEquals(86400, OpenSshConfigFile.timeSpec("1D"));
+ assertEquals(86400, OpenSshConfigFile.timeSpec("1d"));
+ assertEquals(604800, OpenSshConfigFile.timeSpec("1W"));
+ assertEquals(604800, OpenSshConfigFile.timeSpec("1w"));
+ assertEquals(172800, OpenSshConfigFile.timeSpec("2d"));
+ assertEquals(604800, OpenSshConfigFile.timeSpec("1w"));
+ assertEquals(604800 + 172800 + 3 * 3600 + 30 * 60 + 10,
+ OpenSshConfigFile.timeSpec("1w2d3h30m10s"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("-7"));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("-9d"));
+ assertEquals(Integer.MAX_VALUE, OpenSshConfigFile
+ .timeSpec(Integer.toString(Integer.MAX_VALUE)));
+ assertEquals(-1, OpenSshConfigFile
+ .timeSpec(Long.toString(Integer.MAX_VALUE + 1L)));
+ assertEquals(-1, OpenSshConfigFile
+ .timeSpec(Integer.toString(Integer.MAX_VALUE / 60 + 1) + 'M'));
+ assertEquals(-1, OpenSshConfigFile.timeSpec("1000000000000000000000w"));
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java
new file mode 100644
index 0000000..96ace08
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbrevConfigTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.api.errors.InvalidConfigurationException;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.junit.Test;
+
+public class AbbrevConfigTest extends RepositoryTestCase {
+
+ @Test
+ public void testDefault() throws Exception {
+ assertEquals(7, testCoreAbbrev(null));
+ }
+
+ @Test
+ public void testAuto() throws Exception {
+ assertEquals(7, testCoreAbbrev("auto"));
+ }
+
+ @Test
+ public void testNo() throws Exception {
+ assertEquals(40, testCoreAbbrev("no"));
+ }
+
+ @Test
+ public void testValidMin() throws Exception {
+ assertEquals(4, testCoreAbbrev("4"));
+ }
+
+ @Test
+ public void testValid() throws Exception {
+ assertEquals(22, testCoreAbbrev("22"));
+ }
+
+ @Test
+ public void testValidMax() throws Exception {
+ assertEquals(40, testCoreAbbrev("40"));
+ }
+
+ @Test
+ public void testInvalid() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("foo"));
+ }
+
+ @Test
+ public void testInvalid2() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("2k"));
+ }
+
+ @Test
+ public void testInvalidNegative() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("-1000"));
+ }
+
+ @Test
+ public void testInvalidBelowRange() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("3"));
+ }
+
+ @Test
+ public void testInvalidBelowRange2() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("-1"));
+ }
+
+ @Test
+ public void testInvalidAboveRange() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("41"));
+ }
+
+ @Test
+ public void testInvalidAboveRange2() {
+ assertThrows(InvalidConfigurationException.class,
+ () -> testCoreAbbrev("100000"));
+ }
+
+ @Test
+ public void testToStringNo()
+ throws InvalidConfigurationException, IOException {
+ assertEquals("40", setCoreAbbrev("no").toString());
+ }
+
+ @Test
+ public void testToString()
+ throws InvalidConfigurationException, IOException {
+ assertEquals("7", setCoreAbbrev("auto").toString());
+ }
+
+ @Test
+ public void testToString12()
+ throws InvalidConfigurationException, IOException {
+ assertEquals("12", setCoreAbbrev("12").toString());
+ }
+
+ private int testCoreAbbrev(String value)
+ throws InvalidConfigurationException, IOException {
+ return setCoreAbbrev(value).get();
+ }
+
+ private AbbrevConfig setCoreAbbrev(String value)
+ throws IOException, InvalidConfigurationException {
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_ABBREV, value);
+ config.save();
+ return AbbrevConfig.parseFromConfig(db);
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
new file mode 100644
index 0000000..d95d781
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.lib;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
+import org.junit.Test;
+
+public class CommitConfigTest {
+
+ @Test
+ public void testDefaults() throws Exception {
+ CommitConfig cfg = parse("");
+ assertEquals("Unexpected clean-up mode", CleanupMode.DEFAULT,
+ cfg.getCleanupMode());
+ }
+
+ @Test
+ public void testCommitCleanup() throws Exception {
+ String[] values = { "strip", "whitespace", "verbatim", "scissors",
+ "default" };
+ CleanupMode[] expected = { CleanupMode.STRIP, CleanupMode.WHITESPACE,
+ CleanupMode.VERBATIM, CleanupMode.SCISSORS,
+ CleanupMode.DEFAULT };
+ for (int i = 0; i < values.length; i++) {
+ CommitConfig cfg = parse("[commit]\n\tcleanup = " + values[i]);
+ assertEquals("Unexpected clean-up mode", expected[i],
+ cfg.getCleanupMode());
+ }
+ }
+
+ @Test
+ public void testResolve() throws Exception {
+ String[] values = { "strip", "whitespace", "verbatim", "scissors",
+ "default" };
+ CleanupMode[] expected = { CleanupMode.STRIP, CleanupMode.WHITESPACE,
+ CleanupMode.VERBATIM, CleanupMode.SCISSORS,
+ CleanupMode.DEFAULT };
+ for (int i = 0; i < values.length; i++) {
+ CommitConfig cfg = parse("[commit]\n\tcleanup = " + values[i]);
+ for (CleanupMode mode : CleanupMode.values()) {
+ for (int j = 0; j < 2; j++) {
+ CleanupMode resolved = cfg.resolve(mode, j == 0);
+ if (mode != CleanupMode.DEFAULT) {
+ assertEquals("Clean-up mode should be unchanged", mode,
+ resolved);
+ } else if (i + 1 < values.length) {
+ assertEquals("Unexpected clean-up mode", expected[i],
+ resolved);
+ } else {
+ assertEquals("Unexpected clean-up mode",
+ j == 0 ? CleanupMode.STRIP
+ : CleanupMode.WHITESPACE,
+ resolved);
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testCleanDefaultThrows() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> CommitConfig
+ .cleanText("Whatever", CleanupMode.DEFAULT, '#'));
+ }
+
+ @Test
+ public void testCleanVerbatim() throws Exception {
+ String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
+ assertEquals("Unexpected message change", message,
+ CommitConfig.cleanText(message, CleanupMode.VERBATIM, '#'));
+ }
+
+ @Test
+ public void testCleanWhitespace() throws Exception {
+ String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
+ assertEquals("Unexpected message change",
+ "Whatever\n\n# A comment\n\nMore\n",
+ CommitConfig.cleanText(message, CleanupMode.WHITESPACE, '#'));
+ }
+
+ @Test
+ public void testCleanStrip() throws Exception {
+ String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
+ assertEquals("Unexpected message change", "Whatever\n\nMore\n",
+ CommitConfig.cleanText(message, CleanupMode.STRIP, '#'));
+ }
+
+ @Test
+ public void testCleanStripCustomChar() throws Exception {
+ String message = "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n";
+ assertEquals("Unexpected message change",
+ "Whatever\n\n# Not a comment\n\nMore\n",
+ CommitConfig.cleanText(message, CleanupMode.STRIP, '<'));
+ }
+
+ @Test
+ public void testCleanScissors() throws Exception {
+ String message = "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n"
+ + "# ------------------------ >8 ------------------------\n"
+ + "More\nMore\n";
+ assertEquals("Unexpected message change",
+ "Whatever\n\n# Not a comment\n\n <A comment\nMore\n",
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
+ }
+
+ @Test
+ public void testCleanScissorsCustomChar() throws Exception {
+ String message = "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n"
+ + "< ------------------------ >8 ------------------------\n"
+ + "More\nMore\n";
+ assertEquals("Unexpected message change",
+ "Whatever\n\n# Not a comment\n\n <A comment\nMore\n",
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '<'));
+ }
+
+ @Test
+ public void testCleanScissorsAtTop() throws Exception {
+ String message = "# ------------------------ >8 ------------------------\n"
+ + "\n \nWhatever \n\n\n# Not a comment\n\n <A comment\nMore\t \n\n\n"
+ + "More\nMore\n";
+ assertEquals("Unexpected message change", "",
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
+ }
+
+ @Test
+ public void testCleanScissorsNoScissor() throws Exception {
+ String message = "\n \nWhatever \n\n\n# A comment\n\nMore\t \n\n\n";
+ assertEquals("Unexpected message change",
+ "Whatever\n\n# A comment\n\nMore\n",
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
+ }
+
+ @Test
+ public void testCleanScissorsNoScissor2() throws Exception {
+ String message = "Text\n"
+ + "## ------------------------ >8 ------------------------\n"
+ + "More\nMore\n";
+ assertEquals("Unexpected message change", message,
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
+ }
+
+ @Test
+ public void testCleanScissorsNoScissor3() throws Exception {
+ String message = "Text\n"
+ // Wrong number of dashes
+ + "# ----------------------- >8 ------------------------\n"
+ + "More\nMore\n";
+ assertEquals("Unexpected message change", message,
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
+ }
+
+ @Test
+ public void testCleanScissorsAtEnd() throws Exception {
+ String message = "Text\n"
+ + "# ------------------------ >8 ------------------------\n";
+ assertEquals("Unexpected message change", "Text\n",
+ CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
+ }
+
+ private static CommitConfig parse(String content)
+ throws ConfigInvalidException {
+ Config c = new Config();
+ c.fromText(content);
+ return c.get(CommitConfig.KEY);
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitTemplateConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitTemplateConfigTest.java
index 6dbe30a..42bafb6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitTemplateConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitTemplateConfigTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 SAP SE and others
+ * Copyright (C) 2021, 2022 SAP SE and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -47,8 +47,7 @@ public void testCommitTemplatePathInHomeDirecory()
".tmp", new File(homeDir));
tempFileInHomeDirectory.deleteOnExit();
JGitTestUtil.write(tempFileInHomeDirectory, templateContent);
- String expectedTemplatePath = tempFileInHomeDirectory.getPath()
- .replace(homeDir, "~");
+ String expectedTemplatePath = "~/" + tempFileInHomeDirectory.getName();
config = ConfigTest
.parse("[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
String templatePath = config.get(CommitConfig.KEY)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
index 9b82c2a..a85a4f4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
@@ -1488,7 +1488,8 @@ public void testCommitTemplateConfig()
String expectedTemplatePath = tempFile.getPath();
Config config = parse(
- "[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
+ "[commit]\n\ttemplate = "
+ + Config.escapeValue(expectedTemplatePath) + "\n");
String templatePath = config.get(CommitConfig.KEY)
.getCommitTemplatePath();
@@ -1537,7 +1538,8 @@ public void testCommitTemplateEncoding()
JGitTestUtil.write(tempFile, templateContent);
String expectedTemplatePath = tempFile.getPath();
config = parse("[i18n]\n\tcommitEncoding = utf-8\n"
- + "[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
+ + "[commit]\n\ttemplate = "
+ + Config.escapeValue(expectedTemplatePath) + "\n");
assertEquals(templateContent,
config.get(CommitConfig.KEY).getCommitTemplateContent(repo));
String commitEncoding = config.get(CommitConfig.KEY)
@@ -1556,7 +1558,8 @@ public void testCommitTemplateWithInvalidEncoding()
String templateContent = "content of the template";
JGitTestUtil.write(tempFile, templateContent);
config = parse("[i18n]\n\tcommitEncoding = invalidEcoding\n"
- + "[commit]\n\ttemplate = " + tempFile.getPath() + "\n");
+ + "[commit]\n\ttemplate = "
+ + Config.escapeValue(tempFile.getPath()) + "\n");
config.get(CommitConfig.KEY).getCommitTemplateContent(repo);
}
@@ -1570,7 +1573,7 @@ public void testCommitTemplateWithInvalidPath()
String templateContent = "content of the template";
JGitTestUtil.write(tempFile, templateContent);
// commit message encoding
- String expectedTemplatePath = "/nonExistingTemplate";
+ String expectedTemplatePath = "~/nonExistingTemplate";
config = parse("[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
String templatePath = config.get(CommitConfig.KEY)
.getCommitTemplatePath();
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 af8a58f..0fafcd6 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
@@ -2,7 +2,7 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008-2011, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008-2011, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2010, 2020 Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2010, 2022 Christian Halstrick <christian.halstrick@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -242,6 +242,7 @@ public void testInitialCheckout() throws Exception {
ListenerHandle handle = null;
try (Git git = new Git(db);
TestRepository<Repository> db_t = new TestRepository<>(db)) {
+ db.incrementOpen();
handle = db.getListenerList()
.addWorkingTreeModifiedListener(recorder);
BranchBuilder master = db_t.branch("master");
@@ -261,6 +262,7 @@ private void checkoutLineEndings(String inIndex, String expected,
String attributes) throws Exception {
try (Git git = new Git(db);
TestRepository<Repository> db_t = new TestRepository<>(db)) {
+ db.incrementOpen();
BranchBuilder master = db_t.branch("master");
master.commit().add("f", inIndex).message("m0").create();
if (!StringUtils.isEmptyOrNull(attributes)) {
@@ -313,8 +315,9 @@ public void testCheckoutWithLF() throws Exception {
@Test
public void testCheckoutWithLFAuto() throws Exception {
- checkoutLineEndings("first line\nsecond line\n",
- "first line\nsecond line\n", "f text=auto");
+ String expected = String.format("first line%nsecond line%n");
+ checkoutLineEndings("first line\nsecond line\n", expected,
+ "f text=auto");
}
@Test
@@ -325,9 +328,9 @@ public void testCheckoutWithLFAutoEolLf() throws Exception {
@Test
public void testCheckoutWithLFAutoEolNative() throws Exception {
+ String expected = String.format("first line%nsecond line%n");
checkoutLineEndings(
- "first line\nsecond line\n", "first line\nsecond line\n"
- .replaceAll("\n", System.lineSeparator()),
+ "first line\nsecond line\n", expected,
"f text=auto eol=native");
}
@@ -2064,6 +2067,7 @@ public void testResetWithChangeInGitignore() throws Exception {
public void testCheckoutWithEmptyIndexDoesntOverwrite() throws Exception {
try (Git git = new Git(db);
TestRepository<Repository> db_t = new TestRepository<>(db)) {
+ db.incrementOpen();
// prepare the commits
BranchBuilder master = db_t.branch("master");
RevCommit mergeCommit = master.commit()
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java
similarity index 75%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java
index e9bab7c..97da175 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java
@@ -13,12 +13,14 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.time.Instant;
+import java.time.ZoneId;
import java.util.Date;
import java.util.TimeZone;
import org.junit.Test;
-public class T0001_PersonIdentTest {
+public class PersonIdentTest {
@Test
public void test001_NewIdent() {
@@ -42,6 +44,34 @@ public void test002_NewIdent() {
p.toExternalString());
}
+ @Test
+ public void testNewIdentInstant() {
+ PersonIdent p = new PersonIdent("A U Thor", "author@example.com",
+ Instant.ofEpochMilli(1142878501000L),
+ ZoneId.of("America/New_York"));
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(Instant.ofEpochMilli(1142878501000L),
+ p.getWhenAsInstant());
+ assertEquals("A U Thor <author@example.com> 1142878501 -0500",
+ p.toExternalString());
+ assertEquals(ZoneId.of("GMT-05:00"), p.getZoneId());
+ }
+
+ @Test
+ public void testNewIdentInstant2() {
+ final PersonIdent p = new PersonIdent("A U Thor", "author@example.com",
+ Instant.ofEpochMilli(1142878501000L),
+ ZoneId.of("Asia/Kolkata"));
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(Instant.ofEpochMilli(1142878501000L),
+ p.getWhenAsInstant());
+ assertEquals("A U Thor <author@example.com> 1142878501 +0530",
+ p.toExternalString());
+ assertEquals(ZoneId.of("GMT+05:30"), p.getZoneId());
+ }
+
@SuppressWarnings("unused")
@Test(expected = IllegalArgumentException.class)
public void nullForNameShouldThrowIllegalArgumentException() {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
index dedb56c..a2576cc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
@@ -13,6 +13,7 @@
import java.io.IOException;
import java.util.Arrays;
+import java.util.List;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
@@ -157,8 +158,8 @@ public void testIntoSymbolicRefHeadPointingToMaster() throws IOException {
public void testFormatWithConflictsNoFooter() {
String originalMessage = "Header Line\n\nCommit body\n";
String message = formatter.formatWithConflicts(originalMessage,
- Arrays.asList(new String[] { "path1" }));
- assertEquals("Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n",
+ List.of("path1"), '#');
+ assertEquals("Header Line\n\nCommit body\n\n# Conflicts:\n#\tpath1\n",
message);
}
@@ -166,8 +167,17 @@ public void testFormatWithConflictsNoFooter() {
public void testFormatWithConflictsNoFooterNoLineBreak() {
String originalMessage = "Header Line\n\nCommit body";
String message = formatter.formatWithConflicts(originalMessage,
- Arrays.asList(new String[] { "path1" }));
- assertEquals("Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n",
+ List.of("path1"), '#');
+ assertEquals("Header Line\n\nCommit body\n\n# Conflicts:\n#\tpath1\n",
+ message);
+ }
+
+ @Test
+ public void testFormatWithConflictsCustomCharacter() {
+ String originalMessage = "Header Line\n\nCommit body";
+ String message = formatter.formatWithConflicts(originalMessage,
+ List.of("path1"), ';');
+ assertEquals("Header Line\n\nCommit body\n\n; Conflicts:\n;\tpath1\n",
message);
}
@@ -176,9 +186,9 @@ public void testFormatWithConflictsWithFooters() {
String originalMessage = "Header Line\n\nCommit body\n\nChangeId:"
+ " I123456789123456789123456789123456789\nBug:1234567\n";
String message = formatter.formatWithConflicts(originalMessage,
- Arrays.asList(new String[] { "path1" }));
+ List.of("path1"), '#');
assertEquals(
- "Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n\n"
+ "Header Line\n\nCommit body\n\n# Conflicts:\n#\tpath1\n\n"
+ "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n",
message);
}
@@ -188,9 +198,9 @@ public void testFormatWithConflictsWithFooterlikeLineInBody() {
String originalMessage = "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nChangeId:"
+ " I123456789123456789123456789123456789\nBug:1234567\n";
String message = formatter.formatWithConflicts(originalMessage,
- Arrays.asList(new String[] { "path1" }));
+ List.of("path1"), '#');
assertEquals(
- "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nConflicts:\n\tpath1\n\n"
+ "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\n# Conflicts:\n#\tpath1\n\n"
+ "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n",
message);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
index dd8573d..cbacaed 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
@@ -1810,6 +1810,7 @@ private void checkModificationTimeStampOrder(String... pathes) {
private String readBlob(ObjectId treeish, String path) throws Exception {
try (TestRepository<?> tr = new TestRepository<>(db);
RevWalk rw = tr.getRevWalk()) {
+ db.incrementOpen();
RevTree tree = rw.parseTree(treeish);
RevObject obj = tr.get(tree, path);
if (obj == null) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
index ea994f0..f446d07 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
@@ -217,7 +217,6 @@ public void apply(DirCacheEntry ent) {
assertEqualsFile(modulesGitDir, subRepo.getDirectory());
assertEqualsFile(new File(db.getWorkTree(), path),
subRepo.getWorkTree());
- subRepo.close();
assertFalse(gen.next());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
index 054eb9c..bb62a0d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
@@ -80,6 +80,7 @@ public void testWriteSingleRef() throws Exception {
// Then we clone a new repo from that bundle and do a simple test. This
// makes sure we could read the bundle we created.
Repository newRepo = createBareRepository();
+ addRepoToClose(newRepo);
FetchResult fetchResult = fetchFromBundle(newRepo, bundle);
Ref advertisedRef = fetchResult
.getAdvertisedRef("refs/heads/firstcommit");
@@ -116,6 +117,7 @@ public void testIncrementalBundle() throws Exception {
// makes sure
// we could read the bundle we created.
Repository newRepo = createBareRepository();
+ addRepoToClose(newRepo);
FetchResult fetchResult = fetchFromBundle(newRepo, bundle);
Ref advertisedRef = fetchResult.getAdvertisedRef("refs/heads/aa");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
index 60b8098..93bedb3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
@@ -110,6 +110,7 @@ public void test2() throws IOException {
public void testTinyThinPack() throws Exception {
RevBlob a;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
a = d.blob("a");
}
@@ -132,6 +133,7 @@ public void testTinyThinPack() throws Exception {
public void testPackWithDuplicateBlob() throws Exception {
final byte[] data = Constants.encode("0123456789abcdefg");
try (TestRepository<Repository> d = new TestRepository<>(db)) {
+ db.incrementOpen();
assertTrue(db.getObjectDatabase().has(d.blob(data)));
}
@@ -151,6 +153,7 @@ public void testPackWithDuplicateBlob() throws Exception {
public void testPackWithTrailingGarbage() throws Exception {
RevBlob a;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
a = d.blob("a");
}
@@ -180,6 +183,7 @@ public void testPackWithTrailingGarbage() throws Exception {
public void testMaxObjectSizeFullBlob() throws Exception {
final byte[] data = Constants.encode("0123456789");
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
d.blob(data);
}
@@ -213,6 +217,7 @@ public void testMaxObjectSizeFullBlob() throws Exception {
public void testMaxObjectSizeDeltaBlock() throws Exception {
RevBlob a;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
a = d.blob("a");
}
@@ -246,6 +251,7 @@ public void testMaxObjectSizeDeltaBlock() throws Exception {
public void testMaxObjectSizeDeltaResultSize() throws Exception {
RevBlob a;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
a = d.blob("0123456789");
}
@@ -278,6 +284,7 @@ public void testMaxObjectSizeDeltaResultSize() throws Exception {
public void testNonMarkingInputStream() throws Exception {
RevBlob a;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
a = d.blob("a");
}
@@ -318,6 +325,7 @@ public void mark(int maxlength) {
public void testDataAfterPackFooterSingleRead() throws Exception {
RevBlob a;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
a = d.blob("a");
}
@@ -379,6 +387,7 @@ public void testDataAfterPackFooterSplitHeaderRead() throws Exception {
final byte[] data = Constants.encode("a");
RevBlob b;
try (TestRepository d = new TestRepository<Repository>(db)) {
+ db.incrementOpen();
b = d.blob(data);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConfigTest.java
index 6109d6c..cbc1d54 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConfigTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017, David Pursehouse <david.pursehouse@gmail.com> and others
+ * Copyright (C) 2017, 2022 David Pursehouse <david.pursehouse@gmail.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -14,10 +14,13 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.transport.PushConfig.PushDefault;
import org.eclipse.jgit.transport.PushConfig.PushRecurseSubmodulesMode;
import org.junit.Test;
public class PushConfigTest {
+
@Test
public void pushRecurseSubmoduleMatch() throws Exception {
assertTrue(PushRecurseSubmodulesMode.CHECK.matchConfigValue("check"));
@@ -52,4 +55,59 @@ public void pushRecurseSubmoduleToConfigValue() {
assertEquals("check", PushRecurseSubmodulesMode.CHECK.toConfigValue());
assertEquals("false", PushRecurseSubmodulesMode.NO.toConfigValue());
}
+
+ @Test
+ public void pushDefaultMatch() throws Exception {
+ assertTrue(PushDefault.NOTHING.matchConfigValue("nothing"));
+ assertTrue(PushDefault.NOTHING.matchConfigValue("NOTHING"));
+ assertTrue(PushDefault.CURRENT.matchConfigValue("current"));
+ assertTrue(PushDefault.CURRENT.matchConfigValue("CURRENT"));
+ assertTrue(PushDefault.UPSTREAM.matchConfigValue("upstream"));
+ assertTrue(PushDefault.UPSTREAM.matchConfigValue("UPSTREAM"));
+ assertTrue(PushDefault.UPSTREAM.matchConfigValue("tracking"));
+ assertTrue(PushDefault.UPSTREAM.matchConfigValue("TRACKING"));
+ assertTrue(PushDefault.SIMPLE.matchConfigValue("simple"));
+ assertTrue(PushDefault.SIMPLE.matchConfigValue("SIMPLE"));
+ assertTrue(PushDefault.MATCHING.matchConfigValue("matching"));
+ assertTrue(PushDefault.MATCHING.matchConfigValue("MATCHING"));
+ }
+
+ @Test
+ public void pushDefaultNoMatch() throws Exception {
+ assertFalse(PushDefault.NOTHING.matchConfigValue("n"));
+ assertFalse(PushDefault.CURRENT.matchConfigValue(""));
+ assertFalse(PushDefault.UPSTREAM.matchConfigValue("track"));
+ }
+
+ @Test
+ public void pushDefaultToConfigValue() throws Exception {
+ assertEquals("nothing", PushDefault.NOTHING.toConfigValue());
+ assertEquals("current", PushDefault.CURRENT.toConfigValue());
+ assertEquals("upstream", PushDefault.UPSTREAM.toConfigValue());
+ assertEquals("simple", PushDefault.SIMPLE.toConfigValue());
+ assertEquals("matching", PushDefault.MATCHING.toConfigValue());
+ }
+
+ @Test
+ public void testEmptyConfig() throws Exception {
+ PushConfig cfg = parse("");
+ assertEquals(PushRecurseSubmodulesMode.NO, cfg.getRecurseSubmodules());
+ assertEquals(PushDefault.SIMPLE, cfg.getPushDefault());
+ }
+
+ @Test
+ public void testConfig() throws Exception {
+ PushConfig cfg = parse(
+ "[push]\n\tdefault = tracking\n\trecurseSubmodules = on-demand\n");
+ assertEquals(PushRecurseSubmodulesMode.ON_DEMAND,
+ cfg.getRecurseSubmodules());
+ assertEquals(PushDefault.UPSTREAM, cfg.getPushDefault());
+ }
+
+ private static PushConfig parse(String content) throws Exception {
+ Config c = new Config();
+ c.fromText(content);
+ return c.get(PushConfig::new);
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
index 6928859..2e8b30f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
@@ -14,14 +14,19 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.hooks.PrePushHook;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ProgressMonitor;
@@ -31,6 +36,7 @@
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+import org.eclipse.jgit.util.io.NullOutputStream;
import org.junit.Before;
import org.junit.Test;
@@ -220,7 +226,17 @@ public void testUpdateUnexpectedRemoteVsForce() throws IOException {
.fromString("0000000000000000000000000000000000000001"));
final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
- testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
+ try (ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(bytes, true,
+ StandardCharsets.UTF_8);
+ PrintStream err = new PrintStream(NullOutputStream.INSTANCE)) {
+ MockPrePushHook hook = new MockPrePushHook(db, out, err);
+ testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null,
+ hook);
+ out.flush();
+ String result = new String(bytes.toString(StandardCharsets.UTF_8));
+ assertEquals("", result);
+ }
}
/**
@@ -256,10 +272,22 @@ public void testUpdateMixedCases() throws IOException {
refUpdates.add(rruOk);
refUpdates.add(rruReject);
advertisedRefs.add(refToChange);
- executePush();
- assertEquals(Status.OK, rruOk.getStatus());
- assertTrue(rruOk.isFastForward());
- assertEquals(Status.NON_EXISTING, rruReject.getStatus());
+ try (ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(bytes, true,
+ StandardCharsets.UTF_8);
+ PrintStream err = new PrintStream(NullOutputStream.INSTANCE)) {
+ MockPrePushHook hook = new MockPrePushHook(db, out, err);
+ executePush(hook);
+ assertEquals(Status.OK, rruOk.getStatus());
+ assertTrue(rruOk.isFastForward());
+ assertEquals(Status.NON_EXISTING, rruReject.getStatus());
+ out.flush();
+ String result = new String(bytes.toString(StandardCharsets.UTF_8));
+ assertEquals(
+ "null 0000000000000000000000000000000000000000 "
+ + "refs/heads/master 2c349335b7f797072cf729c4f3bb0914ecb6dec9\n",
+ result);
+ }
}
/**
@@ -346,10 +374,18 @@ private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
final Ref advertisedRef, final Status expectedStatus,
Boolean fastForward) throws NotSupportedException,
TransportException {
+ return testOneUpdateStatus(rru, advertisedRef, expectedStatus,
+ fastForward, null);
+ }
+
+ private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
+ final Ref advertisedRef, final Status expectedStatus,
+ Boolean fastForward, PrePushHook hook)
+ throws NotSupportedException, TransportException {
refUpdates.add(rru);
if (advertisedRef != null)
advertisedRefs.add(advertisedRef);
- final PushResult result = executePush();
+ final PushResult result = executePush(hook);
assertEquals(expectedStatus, rru.getStatus());
if (fastForward != null)
assertEquals(fastForward, Boolean.valueOf(rru.isFastForward()));
@@ -358,7 +394,12 @@ private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
private PushResult executePush() throws NotSupportedException,
TransportException {
- process = new PushProcess(transport, refUpdates);
+ return executePush(null);
+ }
+
+ private PushResult executePush(PrePushHook hook)
+ throws NotSupportedException, TransportException {
+ process = new PushProcess(transport, refUpdates, hook);
return process.execute(new TextProgressMonitor());
}
@@ -416,4 +457,20 @@ public void push(ProgressMonitor monitor,
}
}
}
+
+ private static class MockPrePushHook extends PrePushHook {
+
+ private final PrintStream output;
+
+ public MockPrePushHook(Repository repo, PrintStream out,
+ PrintStream err) {
+ super(repo, out, err);
+ output = out;
+ }
+
+ @Override
+ protected void doRun() throws AbortedByHookException, IOException {
+ output.print(getStdinArgs());
+ }
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
index d1e5446..a91bc95 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
@@ -73,11 +73,14 @@ public void setUp() throws Exception {
super.setUp();
src = createBareRepository();
+ addRepoToClose(src);
dst = createBareRepository();
+ addRepoToClose(dst);
// Fill dst with a some common history.
//
try (TestRepository<Repository> d = new TestRepository<>(dst)) {
+ dst.incrementOpen();
a = d.blob("a");
A = d.commit(d.tree(d.file("a", a)));
B = d.commit().parent(A).create();
@@ -106,9 +109,6 @@ public void testFilterHidesPrivate() throws Exception {
dst.getDirectory()) {
@Override
ReceivePack createReceivePack(Repository db) {
- db.close();
- dst.incrementOpen();
-
final ReceivePack rp = super.createReceivePack(dst);
rp.setAdvertiseRefsHook(new HidePrivateHook());
return rp;
@@ -136,8 +136,6 @@ public void resetsHaves() throws Exception {
dst.getDirectory()) {
@Override
ReceivePack createReceivePack(Repository db) {
- dst.incrementOpen();
-
ReceivePack rp = super.createReceivePack(dst);
rp.setAdvertiseRefsHook(new AdvertiseRefsHook() {
@Override
@@ -173,9 +171,6 @@ private TransportLocal newTransportLocalWithStrictValidation()
return new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
@Override
ReceivePack createReceivePack(Repository db) {
- db.close();
- dst.incrementOpen();
-
final ReceivePack rp = super.createReceivePack(dst);
rp.setCheckReceivedObjects(true);
rp.setCheckReferencedObjectsAreReachable(true);
@@ -211,6 +206,7 @@ public void testSuccess() throws Exception {
// Now use b but in a different commit than what is hidden.
//
try (TestRepository<Repository> s = new TestRepository<>(src)) {
+ src.incrementOpen();
RevCommit N = s.commit().parent(B).add("q", b).create();
s.update(R_MASTER, N);
@@ -228,7 +224,6 @@ public void testSuccess() throws Exception {
try (TransportLocal t = newTransportLocalWithStrictValidation()) {
t.setPushThin(true);
r = t.push(PM, Collections.singleton(u));
- dst.close();
}
assertNotNull("have result", r);
@@ -290,6 +285,7 @@ private static void receive(final ReceivePack rp,
public void testUsingHiddenDeltaBaseFails() throws Exception {
byte[] delta = { 0x1, 0x1, 0x1, 'c' };
try (TestRepository<Repository> s = new TestRepository<>(src)) {
+ src.incrementOpen();
RevCommit N = s.commit().parent(B)
.add("q",
s.blob(BinaryDelta.apply(
@@ -348,6 +344,7 @@ public void testUsingHiddenCommonBlobFails() throws Exception {
// Try to use the 'b' blob that is hidden.
//
try (TestRepository<Repository> s = new TestRepository<>(src)) {
+ src.incrementOpen();
RevCommit N = s.commit().parent(B).add("q", s.blob("b")).create();
// But don't include it in the pack.
@@ -401,6 +398,7 @@ public void testUsingUnknownBlobFails() throws Exception {
// Try to use the 'n' blob that is not on the server.
//
try (TestRepository<Repository> s = new TestRepository<>(src)) {
+ src.incrementOpen();
RevBlob n = s.blob("n");
RevCommit N = s.commit().parent(B).add("q", n).create();
@@ -491,6 +489,7 @@ private TemporaryBuffer.Heap setupSourceRepoInvalidGitmodules()
.toString();
try (TestRepository<Repository> s = new TestRepository<>(src)) {
+ src.incrementOpen();
RevBlob blob = s.blob(fakeGitmodules);
RevCommit N = s.commit().parent(B).add(".gitmodules", blob)
.create();
@@ -517,6 +516,7 @@ private TemporaryBuffer.Heap setupSourceRepoInvalidGitmodules()
@Test
public void testUsingUnknownTreeFails() throws Exception {
try (TestRepository<Repository> s = new TestRepository<>(src)) {
+ src.incrementOpen();
RevCommit N = s.commit().parent(B).add("q", s.blob("a")).create();
RevTree t = s.parseBody(N).getTree();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
index 5569bca..b56308c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
@@ -466,4 +466,18 @@ public void onlyWildCard() {
assertTrue(a.matchSource("refs/heads/master"));
assertNull(a.getDestination());
}
+
+ @Test
+ public void matching() {
+ RefSpec a = new RefSpec(":");
+ assertTrue(a.isMatching());
+ assertFalse(a.isForceUpdate());
+ }
+
+ @Test
+ public void matchingForced() {
+ RefSpec a = new RefSpec("+:");
+ assertTrue(a.isMatching());
+ assertTrue(a.isForceUpdate());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java
index 36f94fb..89d31c3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2016, 2022 Christian Halstrick <christian.halstrick@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -10,12 +10,17 @@
package org.eclipse.jgit.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Set;
import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.attributes.FilterCommand;
import org.eclipse.jgit.attributes.FilterCommandFactory;
@@ -86,6 +91,14 @@ public void setUp() throws Exception {
secondCommit = git.commit().setMessage("Second commit").call();
}
+ @Override
+ public void tearDown() throws Exception {
+ Set<String> existingFilters = new HashSet<>(
+ FilterCommandRegistry.getRegisteredFilterCommands());
+ existingFilters.forEach(FilterCommandRegistry::unregister);
+ super.tearDown();
+ }
+
@Test
public void testBuiltinCleanFilter()
throws IOException, GitAPIException {
@@ -217,4 +230,133 @@ public void testBuiltinCleanAndSmudgeFilter() throws IOException, GitAPIExceptio
config.save();
}
+ @Test
+ public void testBranchSwitch() throws Exception {
+ String builtinCommandPrefix = "jgit://builtin/test/";
+ FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
+ new TestCommandFactory('s'));
+ FilterCommandRegistry.register(builtinCommandPrefix + "clean",
+ new TestCommandFactory('c'));
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "test", "smudge",
+ builtinCommandPrefix + "smudge");
+ config.setString("filter", "test", "clean",
+ builtinCommandPrefix + "clean");
+ config.save();
+ // We're on the test branch
+ File aFile = writeTrashFile("a.txt", "a");
+ writeTrashFile(".gitattributes", "a.txt filter=test");
+ File cFile = writeTrashFile("cc/c.txt", "C");
+ writeTrashFile("cc/.gitattributes", "c.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On test").call();
+ git.checkout().setName("master").call();
+ git.branchCreate().setName("other").call();
+ git.checkout().setName("other").call();
+ writeTrashFile("b.txt", "b");
+ writeTrashFile(".gitattributes", "b.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On other").call();
+ git.checkout().setName("test").call();
+ checkFile(aFile, "scsa");
+ checkFile(cFile, "scsC");
+ }
+
+ @Test
+ public void testCheckoutSingleFile() throws Exception {
+ String builtinCommandPrefix = "jgit://builtin/test/";
+ FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
+ new TestCommandFactory('s'));
+ FilterCommandRegistry.register(builtinCommandPrefix + "clean",
+ new TestCommandFactory('c'));
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "test", "smudge",
+ builtinCommandPrefix + "smudge");
+ config.setString("filter", "test", "clean",
+ builtinCommandPrefix + "clean");
+ config.save();
+ // We're on the test branch
+ File aFile = writeTrashFile("a.txt", "a");
+ File attributes = writeTrashFile(".gitattributes", "a.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On test").call();
+ git.checkout().setName("master").call();
+ git.branchCreate().setName("other").call();
+ git.checkout().setName("other").call();
+ writeTrashFile("b.txt", "b");
+ writeTrashFile(".gitattributes", "b.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On other").call();
+ git.checkout().setName("master").call();
+ assertFalse(aFile.exists());
+ assertFalse(attributes.exists());
+ git.checkout().setStartPoint("test").addPath("a.txt").call();
+ checkFile(aFile, "scsa");
+ }
+
+ @Test
+ public void testCheckoutSingleFile2() throws Exception {
+ String builtinCommandPrefix = "jgit://builtin/test/";
+ FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
+ new TestCommandFactory('s'));
+ FilterCommandRegistry.register(builtinCommandPrefix + "clean",
+ new TestCommandFactory('c'));
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "test", "smudge",
+ builtinCommandPrefix + "smudge");
+ config.setString("filter", "test", "clean",
+ builtinCommandPrefix + "clean");
+ config.save();
+ // We're on the test branch
+ File aFile = writeTrashFile("a.txt", "a");
+ File attributes = writeTrashFile(".gitattributes", "a.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On test").call();
+ git.checkout().setName("master").call();
+ git.branchCreate().setName("other").call();
+ git.checkout().setName("other").call();
+ writeTrashFile("b.txt", "b");
+ writeTrashFile(".gitattributes", "b.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On other").call();
+ git.checkout().setName("master").call();
+ assertFalse(aFile.exists());
+ assertFalse(attributes.exists());
+ writeTrashFile(".gitattributes", "");
+ git.checkout().setStartPoint("test").addPath("a.txt").call();
+ checkFile(aFile, "scsa");
+ }
+
+ @Test
+ public void testMerge() throws Exception {
+ String builtinCommandPrefix = "jgit://builtin/test/";
+ FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
+ new TestCommandFactory('s'));
+ FilterCommandRegistry.register(builtinCommandPrefix + "clean",
+ new TestCommandFactory('c'));
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "test", "smudge",
+ builtinCommandPrefix + "smudge");
+ config.setString("filter", "test", "clean",
+ builtinCommandPrefix + "clean");
+ config.save();
+ // We're on the test branch. Set up two branches that are expected to
+ // merge cleanly.
+ File aFile = writeTrashFile("a.txt", "a");
+ writeTrashFile(".gitattributes", "a.txt filter=test");
+ git.add().addFilepattern(".").call();
+ RevCommit aCommit = git.commit().setMessage("On test").call();
+ git.checkout().setName("master").call();
+ assertFalse(aFile.exists());
+ git.branchCreate().setName("other").call();
+ git.checkout().setName("other").call();
+ writeTrashFile("b/b.txt", "b");
+ writeTrashFile("b/.gitattributes", "b.txt filter=test");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("On other").call();
+ MergeResult result = git.merge().include(aCommit).call();
+ assertEquals(MergeResult.MergeStatus.MERGED, result.getMergeStatus());
+ checkFile(aFile, "scsa");
+ }
+
}
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 57a8bee..7baa215 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -4,14 +4,14 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ui
Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Export-Package: org.eclipse.jgit.awtui;version="6.0.1"
-Import-Package: org.eclipse.jgit.errors;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.lib;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.nls;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revplot;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.revwalk;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.transport;version="[6.0.1,6.1.0)",
- org.eclipse.jgit.util;version="[6.0.1,6.1.0)"
+Export-Package: org.eclipse.jgit.awtui;version="6.1.1"
+Import-Package: org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revplot;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.util;version="[6.1.1,6.2.0)"
diff --git a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF
index 335c157..75f3d21 100644
--- a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.ui - Sources
Bundle-SymbolicName: org.eclipse.jgit.ui.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ui;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ui;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index c4a3e2a..125e120 100644
--- a/org.eclipse.jgit.ui/pom.xml
+++ b/org.eclipse.jgit.ui/pom.xml
@@ -19,7 +19,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-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
new file mode 100644
index 0000000..dcb2c51
--- /dev/null
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit" version="2">
+ <resource path="src/org/eclipse/jgit/errors/NoRemoteRepositoryException.java" type="org.eclipse.jgit.errors.NoRemoteRepositoryException">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.1"/>
+ <message_argument value="NoRemoteRepositoryException(URIish, String, Throwable)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="CONFIG_KEY_BITMAP_EXCLUDED_REFS_PREFIXES"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="SHA1_IMPLEMENTATION"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="6.1.1"/>
+ <message_argument value="CONFIG_KEY_TRUST_PACKED_REFS_STAT"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/CoreConfig.java" type="org.eclipse.jgit.lib.CoreConfig$TrustPackedRefsStat">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="6.1.1"/>
+ <message_argument value="TrustPackedRefsStat"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/ObjectDatabase.java" type="org.eclipse.jgit.lib.ObjectDatabase">
+ <filter id="336695337">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.ObjectDatabase"/>
+ <message_argument value="getApproximateObjectCount()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/Repository.java" type="org.eclipse.jgit.lib.Repository">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="getReflogReader(Ref)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/TypedConfigGetter.java" type="org.eclipse.jgit.lib.TypedConfigGetter">
+ <filter id="403767336">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/>
+ <message_argument value="UNSET_INT"/>
+ </message_arguments>
+ </filter>
+ <filter id="403804204">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/>
+ <message_argument value="getIntInRange(Config, String, String, String, int, int, int)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/merge/ResolveMerger.java" type="org.eclipse.jgit.merge.ResolveMerger">
+ <filter id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
+ <message_argument value="addCheckoutMetadata(String, Attributes)"/>
+ </message_arguments>
+ </filter>
+ <filter id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
+ <message_argument value="addToCheckout(String, DirCacheEntry, Attributes)"/>
+ </message_arguments>
+ </filter>
+ <filter id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
+ <message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean, Attributes)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/storage/pack/PackConfig.java" type="org.eclipse.jgit.storage.pack.PackConfig">
+ <filter id="336658481">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.storage.pack.PackConfig"/>
+ <message_argument value="DEFAULT_BITMAP_EXCLUDED_REFS_PREFIXES"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="DEFAULT_BITMAP_EXCLUDED_REFS_PREFIXES"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="getBitmapExcludedRefsPrefixes()"/>
+ </message_arguments>
+ </filter>
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="setBitmapExcludedRefsPrefixes(String[])"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/transport/AwsRequestSignerV4.java" type="org.eclipse.jgit.transport.AwsRequestSignerV4">
+ <filter id="1109393411">
+ <message_arguments>
+ <message_argument value="5.13.1"/>
+ <message_argument value="org.eclipse.jgit.transport.AwsRequestSignerV4"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/transport/BasePackPushConnection.java" type="org.eclipse.jgit.transport.BasePackPushConnection">
+ <filter id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.transport.BasePackPushConnection"/>
+ <message_argument value="noRepository()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/transport/PushConfig.java" type="org.eclipse.jgit.transport.PushConfig">
+ <filter id="338722907">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.transport.PushConfig"/>
+ <message_argument value="PushConfig()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/util/HttpSupport.java" type="org.eclipse.jgit.util.HttpSupport">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.1"/>
+ <message_argument value="urlEncode(String, boolean)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/util/sha1/SHA1.java" type="org.eclipse.jgit.util.sha1.SHA1">
+ <filter id="337764418">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="digest()"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="digest(MutableObjectId)"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="hasCollision()"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="reset()"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="setDetectCollision(boolean)"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="toObjectId()"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="update(byte)"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="update(byte[])"/>
+ </message_arguments>
+ </filter>
+ <filter id="421650549">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.sha1.SHA1"/>
+ <message_argument value="update(byte[], int, int)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/util/sha1/SHA1.java" type="org.eclipse.jgit.util.sha1.SHA1$Sha1Implementation">
+ <filter id="1142947843">
+ <message_arguments>
+ <message_argument value="5.13.2"/>
+ <message_argument value="Sha1Implementation"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 87b58e1..808d5d3 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -3,12 +3,12 @@
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit
Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 6.0.1.qualifier
+Bundle-Version: 6.1.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Eclipse-ExtensibleAPI: true
-Export-Package: org.eclipse.jgit.annotations;version="6.0.1",
- org.eclipse.jgit.api;version="6.0.1";
+Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
+ org.eclipse.jgit.api;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.notes,
org.eclipse.jgit.dircache,
@@ -23,18 +23,18 @@
org.eclipse.jgit.revwalk.filter,
org.eclipse.jgit.blame,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="6.0.1";
+ org.eclipse.jgit.api.errors;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="6.0.1";
+ org.eclipse.jgit.attributes;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.blame;version="6.0.1";
+ org.eclipse.jgit.blame;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="6.0.1";
+ org.eclipse.jgit.diff;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.attributes,
org.eclipse.jgit.revwalk,
@@ -42,44 +42,48 @@
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="6.0.1";
+ org.eclipse.jgit.dircache;version="6.1.1";
uses:="org.eclipse.jgit.events,
org.eclipse.jgit.lib,
org.eclipse.jgit.attributes,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.util",
- org.eclipse.jgit.errors;version="6.0.1";
+ org.eclipse.jgit.errors;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.internal.storage.pack",
- org.eclipse.jgit.events;version="6.0.1";
+ org.eclipse.jgit.events;version="6.1.1";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="6.0.1",
- org.eclipse.jgit.gitrepo;version="6.0.1";
+ org.eclipse.jgit.fnmatch;version="6.1.1",
+ org.eclipse.jgit.gitrepo;version="6.1.1";
uses:="org.xml.sax.helpers,
org.eclipse.jgit.api,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.xml.sax",
- org.eclipse.jgit.gitrepo.internal;version="6.0.1";x-internal:=true,
- org.eclipse.jgit.hooks;version="6.0.1";uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="6.0.1",
- org.eclipse.jgit.ignore.internal;version="6.0.1";
+ org.eclipse.jgit.gitrepo.internal;version="6.1.1";x-internal:=true,
+ org.eclipse.jgit.hooks;version="6.1.1";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="6.1.1",
+ org.eclipse.jgit.ignore.internal;version="6.1.1";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="6.0.1";
+ org.eclipse.jgit.internal;version="6.1.1";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.fsck;version="6.0.1";
+ org.eclipse.jgit.internal.diffmergetool;version="6.1.1";
+ x-friends:="org.eclipse.jgit.test,
+ org.eclipse.jgit.pgm.test,
+ org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.fsck;version="6.1.1";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.revwalk;version="6.0.1";
+ org.eclipse.jgit.internal.revwalk;version="6.1.1";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.storage.dfs;version="6.0.1";
+ org.eclipse.jgit.internal.storage.dfs;version="6.1.1";
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="6.0.1";
+ org.eclipse.jgit.internal.storage.file;version="6.1.1";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http,
@@ -88,32 +92,32 @@
org.eclipse.jgit.pgm,
org.eclipse.jgit.pgm.test,
org.eclipse.jgit.ssh.apache",
- org.eclipse.jgit.internal.storage.io;version="6.0.1";
+ org.eclipse.jgit.internal.storage.io;version="6.1.1";
x-friends:="org.eclipse.jgit.junit,
org.eclipse.jgit.test,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="6.0.1";
+ org.eclipse.jgit.internal.storage.pack;version="6.1.1";
x-friends:="org.eclipse.jgit.junit,
org.eclipse.jgit.test,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftable;version="6.0.1";
+ org.eclipse.jgit.internal.storage.reftable;version="6.1.1";
x-friends:="org.eclipse.jgit.http.test,
org.eclipse.jgit.junit,
org.eclipse.jgit.test,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.submodule;version="6.0.1";x-internal:=true,
- org.eclipse.jgit.internal.transport.connectivity;version="6.0.1";
+ org.eclipse.jgit.internal.submodule;version="6.1.1";x-internal:=true,
+ org.eclipse.jgit.internal.transport.connectivity;version="6.1.1";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.http;version="6.0.1";
+ org.eclipse.jgit.internal.transport.http;version="6.1.1";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.parser;version="6.0.1";
+ org.eclipse.jgit.internal.transport.parser;version="6.1.1";
x-friends:="org.eclipse.jgit.http.server,
org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.ssh;version="6.0.1";
+ org.eclipse.jgit.internal.transport.ssh;version="6.1.1";
x-friends:="org.eclipse.jgit.ssh.apache,
org.eclipse.jgit.ssh.jsch,
org.eclipse.jgit.test",
- org.eclipse.jgit.lib;version="6.0.1";
+ org.eclipse.jgit.lib;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util.sha1,
org.eclipse.jgit.dircache,
@@ -127,10 +131,11 @@
org.eclipse.jgit.util,
org.eclipse.jgit.submodule,
org.eclipse.jgit.util.time",
- org.eclipse.jgit.lib.internal;version="6.0.1";
- x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.logging;version="6.0.1",
- org.eclipse.jgit.merge;version="6.0.1";
+ org.eclipse.jgit.lib.internal;version="6.1.1";
+ x-friends:="org.eclipse.jgit.test,
+ org.eclipse.jgit.pgm",
+ org.eclipse.jgit.logging;version="6.1.1",
+ org.eclipse.jgit.merge;version="6.1.1";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
@@ -139,40 +144,40 @@
org.eclipse.jgit.util,
org.eclipse.jgit.api,
org.eclipse.jgit.attributes",
- org.eclipse.jgit.nls;version="6.0.1",
- org.eclipse.jgit.notes;version="6.0.1";
+ org.eclipse.jgit.nls;version="6.1.1",
+ org.eclipse.jgit.notes;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="6.0.1";
+ org.eclipse.jgit.patch;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="6.0.1";
+ org.eclipse.jgit.revplot;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="6.0.1";
+ org.eclipse.jgit.revwalk;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.diff,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.revwalk.filter,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.revwalk.filter;version="6.0.1";
+ org.eclipse.jgit.revwalk.filter;version="6.1.1";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.lib,
org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="6.0.1";
+ org.eclipse.jgit.storage.file;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="6.0.1";
+ org.eclipse.jgit.storage.pack;version="6.1.1";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="6.0.1";
+ org.eclipse.jgit.submodule;version="6.1.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.diff,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.util",
- org.eclipse.jgit.transport;version="6.0.1";
+ org.eclipse.jgit.transport;version="6.1.1";
uses:="javax.crypto,
org.eclipse.jgit.util.io,
org.eclipse.jgit.lib,
@@ -185,21 +190,21 @@
org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.storage.pack,
org.eclipse.jgit.errors",
- org.eclipse.jgit.transport.http;version="6.0.1";
+ org.eclipse.jgit.transport.http;version="6.1.1";
uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="6.0.1";
+ org.eclipse.jgit.transport.resolver;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.lib",
- org.eclipse.jgit.treewalk;version="6.0.1";
+ org.eclipse.jgit.treewalk;version="6.1.1";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.attributes,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util",
- org.eclipse.jgit.treewalk.filter;version="6.0.1";
+ org.eclipse.jgit.treewalk.filter;version="6.1.1";
uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="6.0.1";
+ org.eclipse.jgit.util;version="6.1.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.hooks,
org.eclipse.jgit.revwalk,
@@ -212,12 +217,12 @@
org.eclipse.jgit.treewalk,
javax.net.ssl,
org.eclipse.jgit.util.time",
- org.eclipse.jgit.util.io;version="6.0.1";
+ org.eclipse.jgit.util.io;version="6.1.1";
uses:="org.eclipse.jgit.attributes,
org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util.sha1;version="6.0.1",
- org.eclipse.jgit.util.time;version="6.0.1"
+ org.eclipse.jgit.util.sha1;version="6.1.1",
+ org.eclipse.jgit.util.time;version="6.1.1"
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
javax.crypto,
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index 302c454..33e6156 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: 6.0.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="6.0.1.qualifier";roots="."
+Bundle-Version: 6.1.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="6.1.1.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index e782272..f0e92b3 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit</artifactId>
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 56701cc..926e3ff 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -356,6 +356,8 @@
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
inputDidntMatchLength=Input did not match supplied length. {0} bytes are missing.
inputStreamMustSupportMark=InputStream must support mark()
+integerValueNotInRange=Integer value {0}.{1} = {2} not in range {3}..{4}
+integerValueNotInRangeSubSection=Integer value {0}.{1}.{2} = {3} not in range {4}..{5}
integerValueOutOfRange=Integer value {0}.{1} out of range
internalRevisionError=internal revision error
internalServerError=internal server error
@@ -367,6 +369,7 @@
invalidBooleanValue=Invalid boolean value: {0}.{1}={2}
invalidChannel=Invalid channel {0}
invalidCommitParentNumber=Invalid commit parent number
+invalidCoreAbbrev=Invalid value {0} of option core.abbrev
invalidDepth=Invalid depth: {0}
invalidEncoding=Invalid encoding from git config i18n.commitEncoding: {0}
invalidEncryption=Invalid encryption
@@ -568,6 +571,11 @@
pushCertificateInvalidFieldValue=Push certificate has missing or invalid value for {0}: {1}
pushCertificateInvalidHeader=Push certificate has invalid header format
pushCertificateInvalidSignature=Push certificate has invalid signature format
+pushDefaultNothing=No refspec given and push.default=nothing; no upstream branch can be determined
+pushDefaultNoUpstream=No upstream branch found for local branch ''{0}''
+pushDefaultSimple=push.default=simple requires local branch name ''{0}'' to be equal to upstream tracked branch name ''{1}''
+pushDefaultTriangularUpstream=push.default=upstream cannot be used when the push remote ''{0}'' is different from the fetch remote ''{1}''
+pushDefaultUnknown=Unknown push.default={0}; cannot push
pushIsNotSupportedForBundleTransport=Push is not supported for bundle transport
pushNotPermitted=push not permitted
pushOptionsNotSupported=Push options not supported; received {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index 7922f9e..f88179a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -9,6 +9,8 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import java.io.IOException;
import java.text.MessageFormat;
import java.util.LinkedList;
@@ -124,7 +126,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
final RevCommit srcParent = getParentCommit(srcCommit, revWalk);
String ourName = calculateOurName(headRef);
- String cherryPickName = srcCommit.getId().abbreviate(7).name()
+ String cherryPickName = srcCommit.getId().abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name()
+ " " + srcCommit.getShortMessage(); //$NON-NLS-1$
Merger merger = strategy.newMerger(repo);
@@ -183,7 +185,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
if (unmergedPaths != null) {
message = new MergeMessageFormatter()
.formatWithConflicts(srcCommit.getFullMessage(),
- unmergedPaths);
+ unmergedPaths, '#');
} else {
message = srcCommit.getFullMessage();
}
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 37f1d48..7a591aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -19,6 +19,7 @@
import java.util.LinkedList;
import java.util.List;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
@@ -46,6 +47,8 @@
import org.eclipse.jgit.hooks.PreCommitHook;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.CommitConfig;
+import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.GpgConfig;
@@ -133,6 +136,12 @@ public class CommitCommand extends GitCommand<RevCommit> {
private CredentialsProvider credentialsProvider;
+ private @NonNull CleanupMode cleanupMode = CleanupMode.VERBATIM;
+
+ private boolean cleanDefaultIsStrip = true;
+
+ private Character commentChar;
+
/**
* Constructor for CommitCommand
*
@@ -200,7 +209,7 @@ public RevCommit call() throws GitAPIException, AbortedByHookException,
throw new WrongRepositoryStateException(
JGitText.get().commitAmendOnInitialNotPossible);
- if (headId != null)
+ if (headId != null) {
if (amend) {
RevCommit previousCommit = rw.parseCommit(headId);
for (RevCommit p : previousCommit.getParents())
@@ -210,7 +219,7 @@ public RevCommit call() throws GitAPIException, AbortedByHookException,
} else {
parents.add(0, headId);
}
-
+ }
if (!noVerify) {
message = Hooks
.commitMsg(repo,
@@ -219,6 +228,19 @@ public RevCommit call() throws GitAPIException, AbortedByHookException,
.setCommitMessage(message).call();
}
+ CommitConfig config = null;
+ if (CleanupMode.DEFAULT.equals(cleanupMode)) {
+ config = repo.getConfig().get(CommitConfig.KEY);
+ cleanupMode = config.resolve(cleanupMode, cleanDefaultIsStrip);
+ }
+ char comments;
+ if (commentChar == null) {
+ comments = '#'; // TODO use git config core.commentChar
+ } else {
+ comments = commentChar.charValue();
+ }
+ message = CommitConfig.cleanText(message, cleanupMode, comments);
+
RevCommit revCommit;
DirCache index = repo.lockDirCache();
try (ObjectInserter odi = repo.newObjectInserter()) {
@@ -658,6 +680,57 @@ public CommitCommand setMessage(String message) {
}
/**
+ * Sets the {@link CleanupMode} to apply to the commit message. If not
+ * called, {@link CommitCommand} applies {@link CleanupMode#VERBATIM}.
+ *
+ * @param mode
+ * {@link CleanupMode} to set
+ * @return {@code this}
+ * @since 6.1
+ */
+ public CommitCommand setCleanupMode(@NonNull CleanupMode mode) {
+ checkCallable();
+ this.cleanupMode = mode;
+ return this;
+ }
+
+ /**
+ * Sets the default clean mode if {@link #setCleanupMode(CleanupMode)
+ * setCleanupMode(CleanupMode.DEFAULT)} is set and git config
+ * {@code commit.cleanup = default} or is not set.
+ *
+ * @param strip
+ * if {@code true}, default to {@link CleanupMode#STRIP};
+ * otherwise default to {@link CleanupMode#WHITESPACE}
+ * @return {@code this}
+ * @since 6.1
+ */
+ public CommitCommand setDefaultClean(boolean strip) {
+ checkCallable();
+ this.cleanDefaultIsStrip = strip;
+ return this;
+ }
+
+ /**
+ * Sets the comment character to apply when cleaning a commit message. If
+ * {@code null} (the default) and the {@link #setCleanupMode(CleanupMode)
+ * clean-up mode} is {@link CleanupMode#STRIP} or
+ * {@link CleanupMode#SCISSORS}, the value of git config
+ * {@code core.commentChar} will be used.
+ *
+ * @param commentChar
+ * the comment character, or {@code null} to use the value from
+ * the git config
+ * @return {@code this}
+ * @since 6.1
+ */
+ public CommitCommand setCommentCharacter(Character commentChar) {
+ checkCallable();
+ this.commentChar = commentChar;
+ return this;
+ }
+
+ /**
* Set whether to allow to create an empty commit
*
* @param allowEmpty
@@ -806,7 +879,7 @@ public CommitCommand setAll(boolean all) {
* command line.
*
* @param amend
- * whether to ammend the tip of the current branch
+ * whether to amend the tip of the current branch
* @return {@code this}
*/
public CommitCommand setAmend(boolean amend) {
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 1e524fa..805a886 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -11,6 +11,7 @@
import static org.eclipse.jgit.lib.Constants.R_REFS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
+import static org.eclipse.jgit.lib.TypedConfigGetter.UNSET_INT;
import java.io.IOException;
import java.text.MessageFormat;
@@ -33,6 +34,7 @@
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.fnmatch.FileNameMatcher;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.AbbrevConfig;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -89,6 +91,11 @@ public class DescribeCommand extends GitCommand<String> {
private boolean always;
/**
+ * The prefix length to use when abbreviating a commit hash.
+ */
+ private int abbrev = UNSET_INT;
+
+ /**
* Constructor for DescribeCommand.
*
* @param repo
@@ -205,12 +212,33 @@ public DescribeCommand setAlways(boolean always) {
return this;
}
+ /**
+ * Sets the prefix length to use when abbreviating an object SHA-1.
+ *
+ * @param abbrev
+ * minimum length of the abbreviated string. Must be in the range
+ * [{@value AbbrevConfig#MIN_ABBREV},
+ * {@value Constants#OBJECT_ID_STRING_LENGTH}].
+ * @return {@code this}
+ * @since 6.1
+ */
+ public DescribeCommand setAbbrev(int abbrev) {
+ if (abbrev == 0) {
+ this.abbrev = 0;
+ } else {
+ this.abbrev = AbbrevConfig.capAbbrev(abbrev);
+ }
+ return this;
+ }
+
private String longDescription(Ref tag, int depth, ObjectId tip)
throws IOException {
- return String.format(
- "%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$
- Integer.valueOf(depth), w.getObjectReader().abbreviate(tip)
- .name());
+ if (abbrev == 0) {
+ return formatRefName(tag.getName());
+ }
+ return String.format("%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$
+ Integer.valueOf(depth),
+ w.getObjectReader().abbreviate(tip, abbrev).name());
}
/**
@@ -302,6 +330,9 @@ public String call() throws GitAPIException {
if (target == null) {
setTarget(Constants.HEAD);
}
+ if (abbrev == UNSET_INT) {
+ abbrev = AbbrevConfig.parseFromConfig(repo).get();
+ }
Collection<Ref> tagList = repo.getRefDatabase()
.getRefsByPrefix(useAll ? R_REFS : R_TAGS);
@@ -413,7 +444,12 @@ String describe(ObjectId tip) throws IOException {
// if all the nodes are dominated by all the tags, the walk stops
if (candidates.isEmpty()) {
- return always ? w.getObjectReader().abbreviate(target).name() : null;
+ return always
+ ? w.getObjectReader()
+ .abbreviate(target,
+ AbbrevConfig.capAbbrev(abbrev))
+ .name()
+ : null;
}
Candidate best = Collections.min(candidates,
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 ef56d80..ce068b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -405,7 +405,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
failingPaths, null);
}
String mergeMessageWithConflicts = new MergeMessageFormatter()
- .formatWithConflicts(mergeMessage, unmergedPaths);
+ .formatWithConflicts(mergeMessage, unmergedPaths, '#');
repo.writeMergeCommitMsg(mergeMessageWithConflicts);
return new MergeResult(null, merger.getBaseCommitId(),
new ObjectId[] { headCommit.getId(),
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
index aa5a634..08353df 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> and others
+ * Copyright (C) 2010, 2022 Chris Aniszczyk <caniszczyk@gmail.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -21,7 +21,9 @@
import java.util.List;
import java.util.Map;
+import org.eclipse.jgit.api.errors.DetachedHeadException;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.NotSupportedException;
@@ -29,11 +31,16 @@
import org.eclipse.jgit.errors.TooLargePackException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.BranchConfig;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PushConfig;
+import org.eclipse.jgit.transport.PushConfig.PushDefault;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefLeaseSpec;
import org.eclipse.jgit.transport.RefSpec;
@@ -52,7 +59,7 @@
public class PushCommand extends
TransportCommand<PushCommand, Iterable<PushResult>> {
- private String remote = Constants.DEFAULT_REMOTE_NAME;
+ private String remote;
private final List<RefSpec> refSpecs;
@@ -71,6 +78,10 @@ public class PushCommand extends
private List<String> pushOptions;
+ // Legacy behavior as default. Use setPushDefault(null) to determine the
+ // value from the git config.
+ private PushDefault pushDefault = PushDefault.CURRENT;
+
/**
* <p>
* Constructor for PushCommand.
@@ -98,19 +109,20 @@ public Iterable<PushResult> call() throws GitAPIException,
InvalidRemoteException,
org.eclipse.jgit.api.errors.TransportException {
checkCallable();
+ setCallable(false);
ArrayList<PushResult> pushResults = new ArrayList<>(3);
try {
+ Config config = repo.getConfig();
+ remote = determineRemote(config, remote);
if (refSpecs.isEmpty()) {
- RemoteConfig config = new RemoteConfig(repo.getConfig(),
+ RemoteConfig rc = new RemoteConfig(config,
getRemote());
- refSpecs.addAll(config.getPushRefSpecs());
- }
- if (refSpecs.isEmpty()) {
- Ref head = repo.exactRef(Constants.HEAD);
- if (head != null && head.isSymbolic())
- refSpecs.add(new RefSpec(head.getLeaf().getName()));
+ refSpecs.addAll(rc.getPushRefSpecs());
+ if (refSpecs.isEmpty()) {
+ determineDefaultRefSpecs(config);
+ }
}
if (force) {
@@ -118,8 +130,8 @@ public Iterable<PushResult> call() throws GitAPIException,
refSpecs.set(i, refSpecs.get(i).setForceUpdate(true));
}
- final List<Transport> transports;
- transports = Transport.openAll(repo, remote, Transport.Operation.PUSH);
+ List<Transport> transports = Transport.openAll(repo, remote,
+ Transport.Operation.PUSH);
for (@SuppressWarnings("resource") // Explicitly closed in finally
final Transport transport : transports) {
transport.setPushThin(thin);
@@ -171,6 +183,102 @@ public Iterable<PushResult> call() throws GitAPIException,
return pushResults;
}
+ private String determineRemote(Config config, String remoteName)
+ throws IOException {
+ if (remoteName != null) {
+ return remoteName;
+ }
+ Ref head = repo.exactRef(Constants.HEAD);
+ String effectiveRemote = null;
+ BranchConfig branchCfg = null;
+ if (head != null && head.isSymbolic()) {
+ String currentBranch = head.getLeaf().getName();
+ branchCfg = new BranchConfig(config,
+ Repository.shortenRefName(currentBranch));
+ effectiveRemote = branchCfg.getPushRemote();
+ }
+ if (effectiveRemote == null) {
+ effectiveRemote = config.getString(
+ ConfigConstants.CONFIG_REMOTE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_PUSH_DEFAULT);
+ if (effectiveRemote == null && branchCfg != null) {
+ effectiveRemote = branchCfg.getRemote();
+ }
+ }
+ if (effectiveRemote == null) {
+ effectiveRemote = Constants.DEFAULT_REMOTE_NAME;
+ }
+ return effectiveRemote;
+ }
+
+ private String getCurrentBranch()
+ throws IOException, DetachedHeadException {
+ Ref head = repo.exactRef(Constants.HEAD);
+ if (head != null && head.isSymbolic()) {
+ return head.getLeaf().getName();
+ }
+ throw new DetachedHeadException();
+ }
+
+ private void determineDefaultRefSpecs(Config config)
+ throws IOException, GitAPIException {
+ if (pushDefault == null) {
+ pushDefault = config.get(PushConfig::new).getPushDefault();
+ }
+ switch (pushDefault) {
+ case CURRENT:
+ refSpecs.add(new RefSpec(getCurrentBranch()));
+ break;
+ case MATCHING:
+ refSpecs.add(new RefSpec(":")); //$NON-NLS-1$
+ break;
+ case NOTHING:
+ throw new InvalidRefNameException(
+ JGitText.get().pushDefaultNothing);
+ case SIMPLE:
+ case UPSTREAM:
+ String currentBranch = getCurrentBranch();
+ BranchConfig branchCfg = new BranchConfig(config,
+ Repository.shortenRefName(currentBranch));
+ String fetchRemote = branchCfg.getRemote();
+ if (fetchRemote == null) {
+ fetchRemote = Constants.DEFAULT_REMOTE_NAME;
+ }
+ boolean isTriangular = !fetchRemote.equals(remote);
+ if (isTriangular) {
+ if (PushDefault.UPSTREAM.equals(pushDefault)) {
+ throw new InvalidRefNameException(MessageFormat.format(
+ JGitText.get().pushDefaultTriangularUpstream,
+ remote, fetchRemote));
+ }
+ // Strange, but consistent with C git: "simple" doesn't even
+ // check whether there is a configured upstream, and if so, that
+ // it is equal to the local branch name. It just becomes
+ // "current".
+ refSpecs.add(new RefSpec(currentBranch));
+ } else {
+ String trackedBranch = branchCfg.getMerge();
+ if (branchCfg.isRemoteLocal() || trackedBranch == null
+ || !trackedBranch.startsWith(Constants.R_HEADS)) {
+ throw new InvalidRefNameException(MessageFormat.format(
+ JGitText.get().pushDefaultNoUpstream,
+ currentBranch));
+ }
+ if (PushDefault.SIMPLE.equals(pushDefault)
+ && !trackedBranch.equals(currentBranch)) {
+ throw new InvalidRefNameException(MessageFormat.format(
+ JGitText.get().pushDefaultSimple, currentBranch,
+ trackedBranch));
+ }
+ refSpecs.add(new RefSpec(currentBranch + ':' + trackedBranch));
+ }
+ break;
+ default:
+ throw new InvalidRefNameException(MessageFormat
+ .format(JGitText.get().pushDefaultUnknown, pushDefault));
+ }
+ }
+
/**
* The remote (uri or name) used for the push operation. If no remote is
* set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will
@@ -336,9 +444,37 @@ public PushCommand setRefSpecs(List<RefSpec> specs) {
}
/**
+ * Retrieves the {@link PushDefault} currently set.
+ *
+ * @return the {@link PushDefault}, or {@code null} if not set
+ * @since 6.1
+ */
+ public PushDefault getPushDefault() {
+ return pushDefault;
+ }
+
+ /**
+ * Sets an explicit {@link PushDefault}. The default used if this is not
+ * called is {@link PushDefault#CURRENT} for compatibility reasons with
+ * earlier JGit versions.
+ *
+ * @param pushDefault
+ * {@link PushDefault} to set; if {@code null} the value defined
+ * in the git config will be used.
+ *
+ * @return {@code this}
+ * @since 6.1
+ */
+ public PushCommand setPushDefault(PushDefault pushDefault) {
+ checkCallable();
+ this.pushDefault = pushDefault;
+ return this;
+ }
+
+ /**
* Push all branches under refs/heads/*.
*
- * @return {code this}
+ * @return {@code this}
*/
public PushCommand setPushAll() {
refSpecs.add(Transport.REFSPEC_PUSH_ALL);
@@ -348,7 +484,7 @@ public PushCommand setPushAll() {
/**
* Push all tags under refs/tags/*.
*
- * @return {code this}
+ * @return {@code this}
*/
public PushCommand setPushTags() {
refSpecs.add(Transport.REFSPEC_TAGS);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index a26ffc2..2b0d8ce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -29,6 +29,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.api.RebaseResult.Status;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
@@ -52,6 +53,8 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.CommitConfig;
+import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -205,6 +208,8 @@ public enum Operation {
private InteractiveHandler interactiveHandler;
+ private CommitConfig commitConfig;
+
private boolean stopAfterInitialization = false;
private RevCommit newHead;
@@ -246,6 +251,7 @@ public RebaseResult call() throws GitAPIException, NoHeadException,
lastStepWasForward = false;
checkCallable();
checkParameters();
+ commitConfig = repo.getConfig().get(CommitConfig.KEY);
try {
switch (operation) {
case ABORT:
@@ -441,11 +447,16 @@ private RebaseResult processStep(RebaseTodoLine step, boolean shouldPick)
return null; // continue rebase process on pick command
case REWORD:
String oldMessage = commitToPick.getFullMessage();
- String newMessage = interactiveHandler
- .modifyCommitMessage(oldMessage);
+ CleanupMode mode = commitConfig.resolve(CleanupMode.DEFAULT, true);
+ boolean[] doChangeId = { false };
+ String newMessage = editCommitMessage(doChangeId, oldMessage, mode);
try (Git git = new Git(repo)) {
- newHead = git.commit().setMessage(newMessage).setAmend(true)
- .setNoVerify(true).call();
+ newHead = git.commit()
+ .setMessage(newMessage)
+ .setAmend(true)
+ .setNoVerify(true)
+ .setInsertChangeId(doChangeId[0])
+ .call();
}
return null;
case EDIT:
@@ -460,17 +471,49 @@ private RebaseResult processStep(RebaseTodoLine step, boolean shouldPick)
resetSoftToParent();
List<RebaseTodoLine> steps = repo.readRebaseTodo(
rebaseState.getPath(GIT_REBASE_TODO), false);
- RebaseTodoLine nextStep = steps.isEmpty() ? null : steps.get(0);
+ boolean isLast = steps.isEmpty();
+ if (!isLast) {
+ switch (steps.get(0).getAction()) {
+ case FIXUP:
+ case SQUASH:
+ break;
+ default:
+ isLast = true;
+ break;
+ }
+ }
File messageFixupFile = rebaseState.getFile(MESSAGE_FIXUP);
File messageSquashFile = rebaseState.getFile(MESSAGE_SQUASH);
- if (isSquash && messageFixupFile.exists())
+ if (isSquash && messageFixupFile.exists()) {
messageFixupFile.delete();
- newHead = doSquashFixup(isSquash, commitToPick, nextStep,
+ }
+ newHead = doSquashFixup(isSquash, commitToPick, isLast,
messageFixupFile, messageSquashFile);
}
return null;
}
+ private String editCommitMessage(boolean[] doChangeId, String message,
+ @NonNull CleanupMode mode) {
+ String newMessage;
+ CommitConfig.CleanupMode cleanup;
+ if (interactiveHandler instanceof InteractiveHandler2) {
+ InteractiveHandler2.ModifyResult modification = ((InteractiveHandler2) interactiveHandler)
+ .editCommitMessage(message, mode, '#');
+ newMessage = modification.getMessage();
+ cleanup = modification.getCleanupMode();
+ if (CleanupMode.DEFAULT.equals(cleanup)) {
+ cleanup = mode;
+ }
+ doChangeId[0] = modification.shouldAddChangeId();
+ } else {
+ newMessage = interactiveHandler.modifyCommitMessage(message);
+ cleanup = CommitConfig.CleanupMode.STRIP;
+ doChangeId[0] = false;
+ }
+ return CommitConfig.cleanText(newMessage, cleanup, '#');
+ }
+
private RebaseResult cherryPickCommit(RevCommit commitToPick)
throws IOException, GitAPIException, NoMessageException,
UnmergedPathsException, ConcurrentRefUpdateException,
@@ -707,7 +750,7 @@ private void checkSteps(List<RebaseTodoLine> steps)
}
private RevCommit doSquashFixup(boolean isSquash, RevCommit commitToPick,
- RebaseTodoLine nextStep, File messageFixup, File messageSquash)
+ boolean isLast, File messageFixup, File messageSquash)
throws IOException, GitAPIException {
if (!messageSquash.exists()) {
@@ -717,24 +760,20 @@ private RevCommit doSquashFixup(boolean isSquash, RevCommit commitToPick,
initializeSquashFixupFile(MESSAGE_SQUASH,
previousCommit.getFullMessage());
- if (!isSquash)
- initializeSquashFixupFile(MESSAGE_FIXUP,
- previousCommit.getFullMessage());
+ if (!isSquash) {
+ rebaseState.createFile(MESSAGE_FIXUP,
+ previousCommit.getFullMessage());
+ }
}
- String currSquashMessage = rebaseState
- .readFile(MESSAGE_SQUASH);
+ String currSquashMessage = rebaseState.readFile(MESSAGE_SQUASH);
int count = parseSquashFixupSequenceCount(currSquashMessage) + 1;
String content = composeSquashMessage(isSquash,
commitToPick, currSquashMessage, count);
rebaseState.createFile(MESSAGE_SQUASH, content);
- if (messageFixup.exists())
- rebaseState.createFile(MESSAGE_FIXUP, content);
- return squashIntoPrevious(
- !messageFixup.exists(),
- nextStep);
+ return squashIntoPrevious(!messageFixup.exists(), isLast);
}
private void resetSoftToParent() throws IOException,
@@ -756,26 +795,30 @@ private void resetSoftToParent() throws IOException,
}
private RevCommit squashIntoPrevious(boolean sequenceContainsSquash,
- RebaseTodoLine nextStep)
+ boolean isLast)
throws IOException, GitAPIException {
RevCommit retNewHead;
- String commitMessage = rebaseState
- .readFile(MESSAGE_SQUASH);
-
+ String commitMessage;
+ if (!isLast || sequenceContainsSquash) {
+ commitMessage = rebaseState.readFile(MESSAGE_SQUASH);
+ } else {
+ commitMessage = rebaseState.readFile(MESSAGE_FIXUP);
+ }
try (Git git = new Git(repo)) {
- if (nextStep == null || ((nextStep.getAction() != Action.FIXUP)
- && (nextStep.getAction() != Action.SQUASH))) {
- // this is the last step in this sequence
+ if (isLast) {
+ boolean[] doChangeId = { false };
if (sequenceContainsSquash) {
- commitMessage = interactiveHandler
- .modifyCommitMessage(commitMessage);
+ commitMessage = editCommitMessage(doChangeId, commitMessage,
+ CleanupMode.STRIP);
}
retNewHead = git.commit()
- .setMessage(stripCommentLines(commitMessage))
- .setAmend(true).setNoVerify(true).call();
+ .setMessage(commitMessage)
+ .setAmend(true)
+ .setNoVerify(true)
+ .setInsertChangeId(doChangeId[0])
+ .call();
rebaseState.getFile(MESSAGE_SQUASH).delete();
rebaseState.getFile(MESSAGE_FIXUP).delete();
-
} else {
// Next step is either Squash or Fixup
retNewHead = git.commit().setMessage(commitMessage)
@@ -785,21 +828,6 @@ private RevCommit squashIntoPrevious(boolean sequenceContainsSquash,
return retNewHead;
}
- private static String stripCommentLines(String commitMessage) {
- StringBuilder result = new StringBuilder();
- for (String line : commitMessage.split("\n")) { //$NON-NLS-1$
- if (!line.trim().startsWith("#")) //$NON-NLS-1$
- result.append(line).append("\n"); //$NON-NLS-1$
- }
- if (!commitMessage.endsWith("\n")) { //$NON-NLS-1$
- int bufferSize = result.length();
- if (bufferSize > 0 && result.charAt(bufferSize - 1) == '\n') {
- result.deleteCharAt(bufferSize - 1);
- }
- }
- return result.toString();
- }
-
@SuppressWarnings("nls")
private static String composeSquashMessage(boolean isSquash,
RevCommit commitToPick, String currSquashMessage, int count) {
@@ -1625,26 +1653,106 @@ public RebaseCommand setPreserveMerges(boolean preserve) {
}
/**
- * Allows configure rebase interactive process and modify commit message
+ * Allows to configure the interactive rebase process steps and to modify
+ * commit messages.
*/
public interface InteractiveHandler {
+
/**
- * Given list of {@code steps} should be modified according to user
- * rebase configuration
+ * Callback API to modify the initial list of interactive rebase steps.
+ *
* @param steps
- * initial configuration of rebase interactive
+ * initial configuration of interactive rebase
*/
void prepareSteps(List<RebaseTodoLine> steps);
/**
- * Used for editing commit message on REWORD
+ * Used for editing commit message on REWORD or SQUASH.
*
- * @param commit
+ * @param message
+ * existing commit message
* @return new commit message
*/
- String modifyCommitMessage(String commit);
+ String modifyCommitMessage(String message);
}
+ /**
+ * Extends {@link InteractiveHandler} with an enhanced callback for editing
+ * commit messages.
+ *
+ * @since 6.1
+ */
+ public interface InteractiveHandler2 extends InteractiveHandler {
+
+ /**
+ * Callback API for editing a commit message on REWORD or SQUASH.
+ * <p>
+ * The callback gets the comment character currently set, and the
+ * clean-up mode. It can use this information when presenting the
+ * message to the user, and it also has the possibility to clean the
+ * message itself (in which case the returned {@link ModifyResult}
+ * should have {@link CleanupMode#VERBATIM} set lest JGit cleans the
+ * message again). It can also override the initial clean-up mode by
+ * returning clean-up mode other than {@link CleanupMode#DEFAULT}. If it
+ * does return {@code DEFAULT}, the passed-in {@code mode} will be
+ * applied.
+ * </p>
+ *
+ * @param message
+ * existing commit message
+ * @param mode
+ * {@link CleanupMode} currently set
+ * @param commentChar
+ * comment character used
+ * @return a {@link ModifyResult}
+ */
+ @NonNull
+ ModifyResult editCommitMessage(@NonNull String message,
+ @NonNull CleanupMode mode, char commentChar);
+
+ @Override
+ default String modifyCommitMessage(String message) {
+ // Should actually not be called; but do something reasonable anyway
+ ModifyResult result = editCommitMessage(
+ message == null ? "" : message, CleanupMode.STRIP, //$NON-NLS-1$
+ '#');
+ return result.getMessage();
+ }
+
+ /**
+ * Describes the result of editing a commit message: the new message,
+ * and how it should be cleaned.
+ */
+ interface ModifyResult {
+
+ /**
+ * Retrieves the new commit message.
+ *
+ * @return the message
+ */
+ @NonNull
+ String getMessage();
+
+ /**
+ * Tells how the message returned by {@link #getMessage()} should be
+ * cleaned.
+ *
+ * @return the {@link CleanupMode}
+ */
+ @NonNull
+ CleanupMode getCleanupMode();
+
+ /**
+ * Tells whether a Gerrit Change-Id should be computed and added to
+ * the commit message, as with
+ * {@link CommitCommand#setInsertChangeId(boolean)}.
+ *
+ * @return {@code true} if a Change-Id should be handled,
+ * {@code false} otherwise
+ */
+ boolean shouldAddChangeId();
+ }
+ }
PersonIdent parseAuthor(byte[] raw) {
if (raw.length == 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
index 22ef4d0..db88ad8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -9,6 +9,8 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import java.io.IOException;
import java.text.MessageFormat;
import java.util.LinkedList;
@@ -128,8 +130,9 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
revWalk.parseHeaders(srcParent);
String ourName = calculateOurName(headRef);
- String revertName = srcCommit.getId().abbreviate(7).name()
- + " " + srcCommit.getShortMessage(); //$NON-NLS-1$
+ String revertName = srcCommit.getId()
+ .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH).name() + " " //$NON-NLS-1$
+ + srcCommit.getShortMessage();
ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
merger.setWorkingTreeIterator(new FileTreeIterator(repo));
@@ -183,8 +186,8 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
merger.getMergeResults(), failingPaths, null);
if (!merger.failed() && !unmergedPaths.isEmpty()) {
String message = new MergeMessageFormatter()
- .formatWithConflicts(newMessage,
- merger.getUnmergedPaths());
+ .formatWithConflicts(newMessage,
+ merger.getUnmergedPaths(), '#');
repo.writeRevertHead(srcCommit.getId());
repo.writeMergeCommitMsg(message);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
index 35fd899..f7a1f4e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -9,6 +9,8 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -302,7 +304,8 @@ public void apply(DirCacheEntry ent) {
builder.setParentId(headCommit);
builder.setTreeId(cache.writeTree(inserter));
builder.setMessage(MessageFormat.format(indexMessage, branch,
- headCommit.abbreviate(7).name(),
+ headCommit.abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH)
+ .name(),
headCommit.getShortMessage()));
ObjectId indexCommit = inserter.insert(builder);
@@ -319,7 +322,10 @@ public void apply(DirCacheEntry ent) {
builder.setParentIds(new ObjectId[0]);
builder.setTreeId(untrackedDirCache.writeTree(inserter));
builder.setMessage(MessageFormat.format(MSG_UNTRACKED,
- branch, headCommit.abbreviate(7).name(),
+ branch,
+ headCommit
+ .abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH)
+ .name(),
headCommit.getShortMessage()));
untrackedCommit = inserter.insert(builder);
}
@@ -339,7 +345,8 @@ public void apply(DirCacheEntry ent) {
builder.addParentId(untrackedCommit);
builder.setMessage(MessageFormat.format(
workingDirectoryMessage, branch,
- headCommit.abbreviate(7).name(),
+ headCommit.abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH)
+ .name(),
headCommit.getShortMessage()));
builder.setTreeId(cache.writeTree(inserter));
commitId = inserter.insert(builder);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
index 638dd82..7ec7859 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
@@ -1,43 +1,11 @@
/*
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ * Copyright (C) 2015, 2022 Ivan Motsch <ivan.motsch@bsiag.com> and others
*
- * 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
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://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.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.attributes;
@@ -46,6 +14,7 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.function.Supplier;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.attributes.Attribute.State;
@@ -84,6 +53,8 @@ public class AttributesHandler {
private final TreeWalk treeWalk;
+ private final Supplier<CanonicalTreeParser> attributesTree;
+
private final AttributesNode globalNode;
private final AttributesNode infoNode;
@@ -98,22 +69,41 @@ public class AttributesHandler {
* @param treeWalk
* a {@link org.eclipse.jgit.treewalk.TreeWalk}
* @throws java.io.IOException
+ * @deprecated since 6.1, use {@link #AttributesHandler(TreeWalk, Supplier)}
+ * instead
*/
+ @Deprecated
public AttributesHandler(TreeWalk treeWalk) throws IOException {
+ this(treeWalk, () -> treeWalk.getTree(CanonicalTreeParser.class));
+ }
+
+ /**
+ * Create an {@link org.eclipse.jgit.attributes.AttributesHandler} with
+ * default rules as well as merged rules from global, info and worktree root
+ * attributes
+ *
+ * @param treeWalk
+ * a {@link org.eclipse.jgit.treewalk.TreeWalk}
+ * @param attributesTree
+ * the tree to read .gitattributes from
+ * @throws java.io.IOException
+ * @since 6.1
+ */
+ public AttributesHandler(TreeWalk treeWalk,
+ Supplier<CanonicalTreeParser> attributesTree) throws IOException {
this.treeWalk = treeWalk;
- AttributesNodeProvider attributesNodeProvider =treeWalk.getAttributesNodeProvider();
+ this.attributesTree = attributesTree;
+ AttributesNodeProvider attributesNodeProvider = treeWalk
+ .getAttributesNodeProvider();
this.globalNode = attributesNodeProvider != null
? attributesNodeProvider.getGlobalAttributesNode() : null;
this.infoNode = attributesNodeProvider != null
? attributesNodeProvider.getInfoAttributesNode() : null;
AttributesNode rootNode = attributesNode(treeWalk,
- rootOf(
- treeWalk.getTree(WorkingTreeIterator.class)),
- rootOf(
- treeWalk.getTree(DirCacheIterator.class)),
- rootOf(treeWalk
- .getTree(CanonicalTreeParser.class)));
+ rootOf(treeWalk.getTree(WorkingTreeIterator.class)),
+ rootOf(treeWalk.getTree(DirCacheIterator.class)),
+ rootOf(attributesTree.get()));
expansions.put(BINARY_RULE_KEY, BINARY_RULE_ATTRIBUTES);
for (AttributesNode node : new AttributesNode[] { globalNode, rootNode,
@@ -152,7 +142,7 @@ public Attributes getAttributes() throws IOException {
isDirectory,
treeWalk.getTree(WorkingTreeIterator.class),
treeWalk.getTree(DirCacheIterator.class),
- treeWalk.getTree(CanonicalTreeParser.class),
+ attributesTree.get(),
attributes);
// Gets the attributes located in the global attribute file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index 49da95c..1a5f74f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -18,6 +18,7 @@
import static org.eclipse.jgit.diff.DiffEntry.ChangeType.RENAME;
import static org.eclipse.jgit.diff.DiffEntry.Side.NEW;
import static org.eclipse.jgit.diff.DiffEntry.Side.OLD;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
import static org.eclipse.jgit.lib.Constants.encode;
import static org.eclipse.jgit.lib.Constants.encodeASCII;
import static org.eclipse.jgit.lib.FileMode.GITLINK;
@@ -90,7 +91,7 @@ public class DiffFormatter implements AutoCloseable {
private int context = 3;
- private int abbreviationLength = 7;
+ private int abbreviationLength = OBJECT_ID_ABBREV_STRING_LENGTH;
private DiffAlgorithm diffAlgorithm;
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 c904a78..3d50a82 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -4,7 +4,8 @@
* Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
* Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2010, Chrisian Halstrick <christian.halstrick@sap.com>
- * Copyright (C) 2019-2020, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2019, 2020, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2017, 2022, Thomas Wolf <thomas.wolf@paranor.ch> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -299,7 +300,7 @@ public void preScanTwoTrees() throws CorruptObjectException, IOException {
walk = new NameConflictTreeWalk(repo);
builder = dc.builder();
- addTree(walk, headCommitTree);
+ walk.setHead(addTree(walk, headCommitTree));
addTree(walk, mergeCommitTree);
int dciPos = walk.addTree(new DirCacheBuildIterator(builder));
walk.addTree(workingTree);
@@ -315,13 +316,6 @@ public void preScanTwoTrees() throws CorruptObjectException, IOException {
}
}
- private void addTree(TreeWalk tw, ObjectId id) throws MissingObjectException, IncorrectObjectTypeException, IOException {
- if (id == null)
- tw.addTree(new EmptyTreeIterator());
- else
- tw.addTree(id);
- }
-
/**
* Scan index and merge tree (no HEAD). Used e.g. for initial checkout when
* there is no head yet.
@@ -341,7 +335,7 @@ public void prescanOneTree()
builder = dc.builder();
walk = new NameConflictTreeWalk(repo);
- addTree(walk, mergeCommitTree);
+ walk.setHead(addTree(walk, mergeCommitTree));
int dciPos = walk.addTree(new DirCacheBuildIterator(builder));
walk.addTree(workingTree);
workingTree.setDirCacheIterator(walk, dciPos);
@@ -356,6 +350,14 @@ public void prescanOneTree()
conflicts.removeAll(removed);
}
+ private int addTree(TreeWalk tw, ObjectId id) throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ if (id == null) {
+ return tw.addTree(new EmptyTreeIterator());
+ }
+ return tw.addTree(id);
+ }
+
/**
* Processing an entry in the context of {@link #prescanOneTree()} when only
* one tree is given
@@ -382,17 +384,14 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
// failOnConflict is false. Putting something to conflicts
// would mean we delete it. Instead we want the mergeCommit
// content to be checked out.
- update(m.getEntryPathString(), m.getEntryObjectId(),
- m.getEntryFileMode());
+ update(m);
}
} else
- update(m.getEntryPathString(), m.getEntryObjectId(),
- m.getEntryFileMode());
+ update(m);
} else if (f == null || !m.idEqual(i)) {
// The working tree file is missing or the merge content differs
// from index content
- update(m.getEntryPathString(), m.getEntryObjectId(),
- m.getEntryFileMode());
+ update(m);
} else if (i.getDirCacheEntry() != null) {
// The index contains a file (and not a folder)
if (f.isModified(i.getDirCacheEntry(), true,
@@ -400,8 +399,7 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
|| i.getDirCacheEntry().getStage() != 0)
// The working tree file is dirty or the index contains a
// conflict
- update(m.getEntryPathString(), m.getEntryObjectId(),
- m.getEntryFileMode());
+ update(m);
else {
// update the timestamp of the index with the one from the
// file if not set, as we are sure to be in sync here.
@@ -802,7 +800,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
if (f != null && isModifiedSubtree_IndexWorkingtree(name)) {
conflict(name, dce, h, m); // 1
} else {
- update(name, mId, mMode); // 2
+ update(1, name, mId, mMode); // 2
}
break;
@@ -828,7 +826,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
// are found later
break;
case 0xD0F: // 19
- update(name, mId, mMode);
+ update(1, name, mId, mMode);
break;
case 0xDF0: // conflict without a rule
case 0x0FD: // 15
@@ -839,7 +837,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
if (isModifiedSubtree_IndexWorkingtree(name))
conflict(name, dce, h, m); // 8
else
- update(name, mId, mMode); // 7
+ update(1, name, mId, mMode); // 7
} else
conflict(name, dce, h, m); // 9
break;
@@ -859,7 +857,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
break;
case 0x0DF: // 16 17
if (!isModifiedSubtree_IndexWorkingtree(name))
- update(name, mId, mMode);
+ update(1, name, mId, mMode);
else
conflict(name, dce, h, m);
break;
@@ -929,7 +927,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
// At least one of Head, Index, Merge is not empty
// -> only Merge contains something for this path. Use it!
// Potentially update the file
- update(name, mId, mMode); // 1
+ update(1, name, mId, mMode); // 1
else if (m == null)
// Nothing in Merge
// Something in Head
@@ -947,7 +945,7 @@ else if (m == null)
// find in Merge. Potentially updates the file.
if (equalIdAndMode(hId, hMode, mId, mMode)) {
if (initialCheckout || force) {
- update(name, mId, mMode);
+ update(1, name, mId, mMode);
} else {
keep(name, dce, f);
}
@@ -1131,7 +1129,7 @@ && isModified_IndexTree(name, iId, iMode, mId, mMode,
// TODO check that we don't overwrite some unsaved
// file content
- update(name, mId, mMode);
+ update(1, name, mId, mMode);
} else if (dce != null
&& (f != null && f.isModified(dce, true,
this.walk.getObjectReader()))) {
@@ -1150,7 +1148,7 @@ && isModified_IndexTree(name, iId, iMode, mId, mMode,
// -> Standard case when switching between branches:
// Nothing new in index but something different in
// Merge. Update index and file
- update(name, mId, mMode);
+ update(1, name, mId, mMode);
}
} else {
// Head differs from index or merge is same as index
@@ -1237,12 +1235,17 @@ private void remove(String path) {
removed.add(path);
}
- private void update(String path, ObjectId mId, FileMode mode)
- throws IOException {
+ private void update(CanonicalTreeParser tree) throws IOException {
+ update(0, tree.getEntryPathString(), tree.getEntryObjectId(),
+ tree.getEntryFileMode());
+ }
+
+ private void update(int index, String path, ObjectId mId,
+ FileMode mode) throws IOException {
if (!FileMode.TREE.equals(mode)) {
updated.put(path, new CheckoutMetadata(
- walk.getEolStreamType(CHECKOUT_OP),
- walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE)));
+ walk.getCheckoutEolStreamType(index),
+ walk.getSmudgeCommand(index)));
DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0);
entry.setObjectId(mId);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java
new file mode 100644
index 0000000..e6626ae
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2021, Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gitrepo;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
+
+import java.io.IOException;
+import java.net.URI;
+import java.text.MessageFormat;
+import java.util.List;
+
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.gitrepo.RepoCommand.ManifestErrorException;
+import org.eclipse.jgit.gitrepo.RepoCommand.RemoteFile;
+import org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader;
+import org.eclipse.jgit.gitrepo.RepoCommand.RemoteUnavailableException;
+import org.eclipse.jgit.gitrepo.RepoProject.CopyFile;
+import org.eclipse.jgit.gitrepo.RepoProject.LinkFile;
+import org.eclipse.jgit.gitrepo.internal.RepoText;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.util.FileUtils;
+
+/**
+ * Writes .gitmodules and gitlinks of parsed manifest projects into a bare
+ * repository.
+ *
+ * To write on a regular repository, see {@link RegularSuperprojectWriter}.
+ */
+class BareSuperprojectWriter {
+ private static final int LOCK_FAILURE_MAX_RETRIES = 5;
+
+ // Retry exponentially with delays in this range
+ private static final int LOCK_FAILURE_MIN_RETRY_DELAY_MILLIS = 50;
+
+ private static final int LOCK_FAILURE_MAX_RETRY_DELAY_MILLIS = 5000;
+
+ private final Repository repo;
+
+ private final URI targetUri;
+
+ private final String targetBranch;
+
+ private final RemoteReader callback;
+
+ private final BareWriterConfig config;
+
+ private final PersonIdent author;
+
+ private List<ExtraContent> extraContents;
+
+ static class BareWriterConfig {
+ boolean ignoreRemoteFailures = false;
+
+ boolean recordRemoteBranch = true;
+
+ boolean recordSubmoduleLabels = true;
+
+ boolean recordShallowSubmodules = true;
+
+ static BareWriterConfig getDefault() {
+ return new BareWriterConfig();
+ }
+
+ private BareWriterConfig() {
+ }
+ }
+
+ static class ExtraContent {
+ final String path;
+
+ final String content;
+
+ ExtraContent(String path, String content) {
+ this.path = path;
+ this.content = content;
+ }
+ }
+
+ BareSuperprojectWriter(Repository repo, URI targetUri,
+ String targetBranch,
+ PersonIdent author, RemoteReader callback,
+ BareWriterConfig config,
+ List<ExtraContent> extraContents) {
+ assert (repo.isBare());
+ this.repo = repo;
+ this.targetUri = targetUri;
+ this.targetBranch = targetBranch;
+ this.author = author;
+ this.callback = callback;
+ this.config = config;
+ this.extraContents = extraContents;
+ }
+
+ RevCommit write(List<RepoProject> repoProjects)
+ throws GitAPIException {
+ DirCache index = DirCache.newInCore();
+ ObjectInserter inserter = repo.newObjectInserter();
+
+ try (RevWalk rw = new RevWalk(repo)) {
+ prepareIndex(repoProjects, index, inserter);
+ ObjectId treeId = index.writeTree(inserter);
+ long prevDelay = 0;
+ for (int i = 0; i < LOCK_FAILURE_MAX_RETRIES - 1; i++) {
+ try {
+ return commitTreeOnCurrentTip(inserter, rw, treeId);
+ } catch (ConcurrentRefUpdateException e) {
+ prevDelay = FileUtils.delay(prevDelay,
+ LOCK_FAILURE_MIN_RETRY_DELAY_MILLIS,
+ LOCK_FAILURE_MAX_RETRY_DELAY_MILLIS);
+ Thread.sleep(prevDelay);
+ repo.getRefDatabase().refresh();
+ }
+ }
+ // In the last try, just propagate the exceptions
+ return commitTreeOnCurrentTip(inserter, rw, treeId);
+ } catch (IOException | InterruptedException e) {
+ throw new ManifestErrorException(e);
+ }
+ }
+
+ private void prepareIndex(List<RepoProject> projects, DirCache index,
+ ObjectInserter inserter) throws IOException, GitAPIException {
+ Config cfg = new Config();
+ StringBuilder attributes = new StringBuilder();
+ DirCacheBuilder builder = index.builder();
+ for (RepoProject proj : projects) {
+ String name = proj.getName();
+ String path = proj.getPath();
+ String url = proj.getUrl();
+ ObjectId objectId;
+ if (ObjectId.isId(proj.getRevision())) {
+ objectId = ObjectId.fromString(proj.getRevision());
+ } else {
+ objectId = callback.sha1(url, proj.getRevision());
+ if (objectId == null && !config.ignoreRemoteFailures) {
+ throw new RemoteUnavailableException(url);
+ }
+ if (config.recordRemoteBranch) {
+ // "branch" field is only for non-tag references.
+ // Keep tags in "ref" field as hint for other tools.
+ String field = proj.getRevision().startsWith(R_TAGS) ? "ref" //$NON-NLS-1$
+ : "branch"; //$NON-NLS-1$
+ cfg.setString("submodule", name, field, //$NON-NLS-1$
+ proj.getRevision());
+ }
+
+ if (config.recordShallowSubmodules
+ && proj.getRecommendShallow() != null) {
+ // The shallow recommendation is losing information.
+ // As the repo manifests stores the recommended
+ // depth in the 'clone-depth' field, while
+ // git core only uses a binary 'shallow = true/false'
+ // hint, we'll map any depth to 'shallow = true'
+ cfg.setBoolean("submodule", name, "shallow", //$NON-NLS-1$ //$NON-NLS-2$
+ true);
+ }
+ }
+ if (config.recordSubmoduleLabels) {
+ StringBuilder rec = new StringBuilder();
+ rec.append("/"); //$NON-NLS-1$
+ rec.append(path);
+ for (String group : proj.getGroups()) {
+ rec.append(" "); //$NON-NLS-1$
+ rec.append(group);
+ }
+ rec.append("\n"); //$NON-NLS-1$
+ attributes.append(rec.toString());
+ }
+
+ URI submodUrl = URI.create(url);
+ if (targetUri != null) {
+ submodUrl = RepoCommand.relativize(targetUri, submodUrl);
+ }
+ cfg.setString("submodule", name, "path", path); //$NON-NLS-1$ //$NON-NLS-2$
+ cfg.setString("submodule", name, "url", //$NON-NLS-1$ //$NON-NLS-2$
+ submodUrl.toString());
+
+ // create gitlink
+ if (objectId != null) {
+ DirCacheEntry dcEntry = new DirCacheEntry(path);
+ dcEntry.setObjectId(objectId);
+ dcEntry.setFileMode(FileMode.GITLINK);
+ builder.add(dcEntry);
+
+ for (CopyFile copyfile : proj.getCopyFiles()) {
+ RemoteFile rf = callback.readFileWithMode(url,
+ proj.getRevision(), copyfile.src);
+ objectId = inserter.insert(Constants.OBJ_BLOB,
+ rf.getContents());
+ dcEntry = new DirCacheEntry(copyfile.dest);
+ dcEntry.setObjectId(objectId);
+ dcEntry.setFileMode(rf.getFileMode());
+ builder.add(dcEntry);
+ }
+ for (LinkFile linkfile : proj.getLinkFiles()) {
+ String link;
+ if (linkfile.dest.contains("/")) { //$NON-NLS-1$
+ link = FileUtils.relativizeGitPath(
+ linkfile.dest.substring(0,
+ linkfile.dest.lastIndexOf('/')),
+ proj.getPath() + "/" + linkfile.src); //$NON-NLS-1$
+ } else {
+ link = proj.getPath() + "/" + linkfile.src; //$NON-NLS-1$
+ }
+
+ objectId = inserter.insert(Constants.OBJ_BLOB,
+ link.getBytes(UTF_8));
+ dcEntry = new DirCacheEntry(linkfile.dest);
+ dcEntry.setObjectId(objectId);
+ dcEntry.setFileMode(FileMode.SYMLINK);
+ builder.add(dcEntry);
+ }
+ }
+ }
+ String content = cfg.toText();
+
+ // create a new DirCacheEntry for .gitmodules file.
+ DirCacheEntry dcEntry = new DirCacheEntry(
+ Constants.DOT_GIT_MODULES);
+ ObjectId objectId = inserter.insert(Constants.OBJ_BLOB,
+ content.getBytes(UTF_8));
+ dcEntry.setObjectId(objectId);
+ dcEntry.setFileMode(FileMode.REGULAR_FILE);
+ builder.add(dcEntry);
+
+ if (config.recordSubmoduleLabels) {
+ // create a new DirCacheEntry for .gitattributes file.
+ DirCacheEntry dcEntryAttr = new DirCacheEntry(
+ Constants.DOT_GIT_ATTRIBUTES);
+ ObjectId attrId = inserter.insert(Constants.OBJ_BLOB,
+ attributes.toString().getBytes(UTF_8));
+ dcEntryAttr.setObjectId(attrId);
+ dcEntryAttr.setFileMode(FileMode.REGULAR_FILE);
+ builder.add(dcEntryAttr);
+ }
+
+ for (ExtraContent ec : extraContents) {
+ DirCacheEntry extraDcEntry = new DirCacheEntry(ec.path);
+
+ ObjectId oid = inserter.insert(Constants.OBJ_BLOB,
+ ec.content.getBytes(UTF_8));
+ extraDcEntry.setObjectId(oid);
+ extraDcEntry.setFileMode(FileMode.REGULAR_FILE);
+ builder.add(extraDcEntry);
+ }
+
+ builder.finish();
+ }
+
+ private RevCommit commitTreeOnCurrentTip(ObjectInserter inserter,
+ RevWalk rw, ObjectId treeId)
+ throws IOException, ConcurrentRefUpdateException {
+ ObjectId headId = repo.resolve(targetBranch + "^{commit}"); //$NON-NLS-1$
+ if (headId != null
+ && rw.parseCommit(headId).getTree().getId().equals(treeId)) {
+ // No change. Do nothing.
+ return rw.parseCommit(headId);
+ }
+
+ CommitBuilder commit = new CommitBuilder();
+ commit.setTreeId(treeId);
+ if (headId != null) {
+ commit.setParentIds(headId);
+ }
+ commit.setAuthor(author);
+ commit.setCommitter(author);
+ commit.setMessage(RepoText.get().repoCommitMessage);
+
+ ObjectId commitId = inserter.insert(commit);
+ inserter.flush();
+
+ RefUpdate ru = repo.updateRef(targetBranch);
+ ru.setNewObjectId(commitId);
+ ru.setExpectedOldObjectId(headId != null ? headId : ObjectId.zeroId());
+ Result rc = ru.update(rw);
+ switch (rc) {
+ case NEW:
+ case FORCED:
+ case FAST_FORWARD:
+ // Successful. Do nothing.
+ break;
+ case REJECTED:
+ case LOCK_FAILURE:
+ throw new ConcurrentRefUpdateException(MessageFormat.format(
+ JGitText.get().cannotLock, targetBranch), ru.getRef(), rc);
+ default:
+ throw new JGitInternalException(
+ MessageFormat.format(JGitText.get().updatingRefFailed,
+ targetBranch, commitId.name(), rc));
+ }
+
+ return rw.parseCommit(commitId);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RegularSuperprojectWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RegularSuperprojectWriter.java
new file mode 100644
index 0000000..afab994
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RegularSuperprojectWriter.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021, Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.gitrepo;
+
+import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME;
+import static org.eclipse.jgit.lib.Constants.R_REMOTES;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.SubmoduleAddCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.gitrepo.RepoCommand.ManifestErrorException;
+import org.eclipse.jgit.gitrepo.RepoProject.CopyFile;
+import org.eclipse.jgit.gitrepo.RepoProject.LinkFile;
+import org.eclipse.jgit.gitrepo.internal.RepoText;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+/**
+ * Writes .gitmodules and gitlinks of parsed manifest projects into a regular
+ * repository (using git submodule commands)
+ *
+ * To write on a bare repository, use {@link BareSuperprojectWriter}
+ */
+class RegularSuperprojectWriter {
+
+ private Repository repo;
+
+ private ProgressMonitor monitor;
+
+ RegularSuperprojectWriter(Repository repo, ProgressMonitor monitor) {
+ this.repo = repo;
+ this.monitor = monitor;
+ }
+
+ RevCommit write(List<RepoProject> repoProjects)
+ throws GitAPIException {
+ try (Git git = new Git(repo)) {
+ for (RepoProject proj : repoProjects) {
+ addSubmodule(proj.getName(), proj.getUrl(), proj.getPath(),
+ proj.getRevision(), proj.getCopyFiles(),
+ proj.getLinkFiles(), git);
+ }
+ return git.commit().setMessage(RepoText.get().repoCommitMessage)
+ .call();
+ } catch (IOException e) {
+ throw new ManifestErrorException(e);
+ }
+ }
+
+ private void addSubmodule(String name, String url, String path,
+ String revision, List<CopyFile> copyfiles, List<LinkFile> linkfiles,
+ Git git) throws GitAPIException, IOException {
+ assert (!repo.isBare());
+ assert (git != null);
+ if (!linkfiles.isEmpty()) {
+ throw new UnsupportedOperationException(
+ JGitText.get().nonBareLinkFilesNotSupported);
+ }
+
+ SubmoduleAddCommand add = git.submoduleAdd().setName(name).setPath(path)
+ .setURI(url);
+ if (monitor != null) {
+ add.setProgressMonitor(monitor);
+ }
+
+ Repository subRepo = add.call();
+ if (revision != null) {
+ try (Git sub = new Git(subRepo)) {
+ sub.checkout().setName(findRef(revision, subRepo)).call();
+ }
+ subRepo.close();
+ git.add().addFilepattern(path).call();
+ }
+ for (CopyFile copyfile : copyfiles) {
+ copyfile.copy();
+ git.add().addFilepattern(copyfile.dest).call();
+ }
+ }
+
+ private static String findRef(String ref, Repository repo)
+ throws IOException {
+ if (!ObjectId.isId(ref)) {
+ Ref r = repo.exactRef(R_REMOTES + DEFAULT_REMOTE_NAME + "/" + ref); //$NON-NLS-1$
+ if (r != null) {
+ return r.getName();
+ }
+ }
+ return ref;
+ }
+}
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 e0a8224..6e943e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -9,11 +9,6 @@
*/
package org.eclipse.jgit.gitrepo;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME;
-import static org.eclipse.jgit.lib.Constants.R_REMOTES;
-import static org.eclipse.jgit.lib.Constants.R_TAGS;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -31,34 +26,21 @@
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.GitCommand;
-import org.eclipse.jgit.api.SubmoduleAddCommand;
-import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
-import org.eclipse.jgit.api.errors.JGitInternalException;
-import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
-import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.gitrepo.BareSuperprojectWriter.ExtraContent;
import org.eclipse.jgit.gitrepo.ManifestParser.IncludedFileReader;
-import org.eclipse.jgit.gitrepo.RepoProject.CopyFile;
-import org.eclipse.jgit.gitrepo.RepoProject.LinkFile;
import org.eclipse.jgit.gitrepo.internal.RepoText;
import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.lib.CommitBuilder;
-import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
-import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FileUtils;
@@ -80,12 +62,7 @@
* @since 3.4
*/
public class RepoCommand extends GitCommand<RevCommit> {
- private static final int LOCK_FAILURE_MAX_RETRIES = 5;
- // Retry exponentially with delays in this range
- private static final int LOCK_FAILURE_MIN_RETRY_DELAY_MILLIS = 50;
-
- private static final int LOCK_FAILURE_MAX_RETRY_DELAY_MILLIS = 5000;
private String manifestPath;
private String baseUri;
@@ -93,17 +70,18 @@ public class RepoCommand extends GitCommand<RevCommit> {
private String groupsParam;
private String branch;
private String targetBranch = Constants.HEAD;
- private boolean recordRemoteBranch = true;
- private boolean recordSubmoduleLabels = true;
- private boolean recordShallowSubmodules = true;
private PersonIdent author;
private RemoteReader callback;
private InputStream inputStream;
private IncludedFileReader includedReader;
- private boolean ignoreRemoteFailures = false;
+
+ private BareSuperprojectWriter.BareWriterConfig bareWriterConfig = BareSuperprojectWriter.BareWriterConfig
+ .getDefault();
private ProgressMonitor monitor;
+ private final List<ExtraContent> extraContents = new ArrayList<>();
+
/**
* A callback to get ref sha1 of a repository from its uri.
*
@@ -269,14 +247,14 @@ public RemoteFile readFileWithMode(String uri, String ref, String path)
}
@SuppressWarnings("serial")
- private static class ManifestErrorException extends GitAPIException {
+ static class ManifestErrorException extends GitAPIException {
ManifestErrorException(Throwable cause) {
super(RepoText.get().invalidManifest, cause);
}
}
@SuppressWarnings("serial")
- private static class RemoteUnavailableException extends GitAPIException {
+ static class RemoteUnavailableException extends GitAPIException {
RemoteUnavailableException(String uri) {
super(MessageFormat.format(RepoText.get().errorRemoteUnavailable, uri));
}
@@ -421,7 +399,7 @@ public RepoCommand setTargetBranch(String branch) {
* @since 4.2
*/
public RepoCommand setRecordRemoteBranch(boolean enable) {
- this.recordRemoteBranch = enable;
+ this.bareWriterConfig.recordRemoteBranch = enable;
return this;
}
@@ -436,7 +414,7 @@ public RepoCommand setRecordRemoteBranch(boolean enable) {
* @since 4.4
*/
public RepoCommand setRecordSubmoduleLabels(boolean enable) {
- this.recordSubmoduleLabels = enable;
+ this.bareWriterConfig.recordSubmoduleLabels = enable;
return this;
}
@@ -451,7 +429,7 @@ public RepoCommand setRecordSubmoduleLabels(boolean enable) {
* @since 4.4
*/
public RepoCommand setRecommendShallow(boolean enable) {
- this.recordShallowSubmodules = enable;
+ this.bareWriterConfig.recordShallowSubmodules = enable;
return this;
}
@@ -485,7 +463,7 @@ public RepoCommand setProgressMonitor(ProgressMonitor monitor) {
* @since 4.3
*/
public RepoCommand setIgnoreRemoteFailures(boolean ignore) {
- this.ignoreRemoteFailures = ignore;
+ this.bareWriterConfig.ignoreRemoteFailures = ignore;
return this;
}
@@ -534,6 +512,22 @@ public RepoCommand setIncludedFileReader(IncludedFileReader reader) {
return this;
}
+ /**
+ * Create a file with the given content in the destination repository
+ *
+ * @param path
+ * where to create the file in the destination repository
+ * @param contents
+ * content for the create file
+ * @return this command
+ *
+ * @since 6.1
+ */
+ public RepoCommand addToDestination(String path, String contents) {
+ this.extraContents.add(new ExtraContent(path, contents));
+ return this;
+ }
+
/** {@inheritDoc} */
@Override
public RevCommit call() throws GitAPIException {
@@ -570,240 +564,18 @@ public RevCommit call() throws GitAPIException {
}
if (repo.isBare()) {
- if (author == null)
- author = new PersonIdent(repo);
- if (callback == null)
- callback = new DefaultRemoteReader();
List<RepoProject> renamedProjects = renameProjects(filteredProjects);
-
- DirCache index = DirCache.newInCore();
- ObjectInserter inserter = repo.newObjectInserter();
-
- try (RevWalk rw = new RevWalk(repo)) {
- prepareIndex(renamedProjects, index, inserter);
- ObjectId treeId = index.writeTree(inserter);
- long prevDelay = 0;
- for (int i = 0; i < LOCK_FAILURE_MAX_RETRIES - 1; i++) {
- try {
- return commitTreeOnCurrentTip(
- inserter, rw, treeId);
- } catch (ConcurrentRefUpdateException e) {
- prevDelay = FileUtils.delay(prevDelay,
- LOCK_FAILURE_MIN_RETRY_DELAY_MILLIS,
- LOCK_FAILURE_MAX_RETRY_DELAY_MILLIS);
- Thread.sleep(prevDelay);
- repo.getRefDatabase().refresh();
- }
- }
- // In the last try, just propagate the exceptions
- return commitTreeOnCurrentTip(inserter, rw, treeId);
- } catch (IOException | InterruptedException e) {
- throw new ManifestErrorException(e);
- }
- }
- try (Git git = new Git(repo)) {
- for (RepoProject proj : filteredProjects) {
- addSubmodule(proj.getName(), proj.getUrl(), proj.getPath(),
- proj.getRevision(), proj.getCopyFiles(),
- proj.getLinkFiles(), git);
- }
- return git.commit().setMessage(RepoText.get().repoCommitMessage)
- .call();
- } catch (IOException e) {
- throw new ManifestErrorException(e);
- }
- }
-
- private void prepareIndex(List<RepoProject> projects, DirCache index,
- ObjectInserter inserter) throws IOException, GitAPIException {
- Config cfg = new Config();
- StringBuilder attributes = new StringBuilder();
- DirCacheBuilder builder = index.builder();
- for (RepoProject proj : projects) {
- String name = proj.getName();
- String path = proj.getPath();
- String url = proj.getUrl();
- ObjectId objectId;
- if (ObjectId.isId(proj.getRevision())) {
- objectId = ObjectId.fromString(proj.getRevision());
- } else {
- objectId = callback.sha1(url, proj.getRevision());
- if (objectId == null && !ignoreRemoteFailures) {
- throw new RemoteUnavailableException(url);
- }
- if (recordRemoteBranch) {
- // "branch" field is only for non-tag references.
- // Keep tags in "ref" field as hint for other tools.
- String field = proj.getRevision().startsWith(R_TAGS) ? "ref" //$NON-NLS-1$
- : "branch"; //$NON-NLS-1$
- cfg.setString("submodule", name, field, //$NON-NLS-1$
- proj.getRevision());
- }
-
- if (recordShallowSubmodules
- && proj.getRecommendShallow() != null) {
- // The shallow recommendation is losing information.
- // As the repo manifests stores the recommended
- // depth in the 'clone-depth' field, while
- // git core only uses a binary 'shallow = true/false'
- // hint, we'll map any depth to 'shallow = true'
- cfg.setBoolean("submodule", name, "shallow", //$NON-NLS-1$ //$NON-NLS-2$
- true);
- }
- }
- if (recordSubmoduleLabels) {
- StringBuilder rec = new StringBuilder();
- rec.append("/"); //$NON-NLS-1$
- rec.append(path);
- for (String group : proj.getGroups()) {
- rec.append(" "); //$NON-NLS-1$
- rec.append(group);
- }
- rec.append("\n"); //$NON-NLS-1$
- attributes.append(rec.toString());
- }
-
- URI submodUrl = URI.create(url);
- if (targetUri != null) {
- submodUrl = relativize(targetUri, submodUrl);
- }
- cfg.setString("submodule", name, "path", path); //$NON-NLS-1$ //$NON-NLS-2$
- cfg.setString("submodule", name, "url", //$NON-NLS-1$ //$NON-NLS-2$
- submodUrl.toString());
-
- // create gitlink
- if (objectId != null) {
- DirCacheEntry dcEntry = new DirCacheEntry(path);
- dcEntry.setObjectId(objectId);
- dcEntry.setFileMode(FileMode.GITLINK);
- builder.add(dcEntry);
-
- for (CopyFile copyfile : proj.getCopyFiles()) {
- RemoteFile rf = callback.readFileWithMode(url,
- proj.getRevision(), copyfile.src);
- objectId = inserter.insert(Constants.OBJ_BLOB,
- rf.getContents());
- dcEntry = new DirCacheEntry(copyfile.dest);
- dcEntry.setObjectId(objectId);
- dcEntry.setFileMode(rf.getFileMode());
- builder.add(dcEntry);
- }
- for (LinkFile linkfile : proj.getLinkFiles()) {
- String link;
- if (linkfile.dest.contains("/")) { //$NON-NLS-1$
- link = FileUtils.relativizeGitPath(
- linkfile.dest.substring(0,
- linkfile.dest.lastIndexOf('/')),
- proj.getPath() + "/" + linkfile.src); //$NON-NLS-1$
- } else {
- link = proj.getPath() + "/" + linkfile.src; //$NON-NLS-1$
- }
-
- objectId = inserter.insert(Constants.OBJ_BLOB,
- link.getBytes(UTF_8));
- dcEntry = new DirCacheEntry(linkfile.dest);
- dcEntry.setObjectId(objectId);
- dcEntry.setFileMode(FileMode.SYMLINK);
- builder.add(dcEntry);
- }
- }
- }
- String content = cfg.toText();
-
- // create a new DirCacheEntry for .gitmodules file.
- DirCacheEntry dcEntry = new DirCacheEntry(
- Constants.DOT_GIT_MODULES);
- ObjectId objectId = inserter.insert(Constants.OBJ_BLOB,
- content.getBytes(UTF_8));
- dcEntry.setObjectId(objectId);
- dcEntry.setFileMode(FileMode.REGULAR_FILE);
- builder.add(dcEntry);
-
- if (recordSubmoduleLabels) {
- // create a new DirCacheEntry for .gitattributes file.
- DirCacheEntry dcEntryAttr = new DirCacheEntry(
- Constants.DOT_GIT_ATTRIBUTES);
- ObjectId attrId = inserter.insert(Constants.OBJ_BLOB,
- attributes.toString().getBytes(UTF_8));
- dcEntryAttr.setObjectId(attrId);
- dcEntryAttr.setFileMode(FileMode.REGULAR_FILE);
- builder.add(dcEntryAttr);
+ BareSuperprojectWriter writer = new BareSuperprojectWriter(repo, targetUri,
+ targetBranch,
+ author == null ? new PersonIdent(repo) : author,
+ callback == null ? new DefaultRemoteReader() : callback,
+ bareWriterConfig, extraContents);
+ return writer.write(renamedProjects);
}
- builder.finish();
- }
- private RevCommit commitTreeOnCurrentTip(ObjectInserter inserter,
- RevWalk rw, ObjectId treeId)
- throws IOException, ConcurrentRefUpdateException {
- ObjectId headId = repo.resolve(targetBranch + "^{commit}"); //$NON-NLS-1$
- if (headId != null && rw.parseCommit(headId).getTree().getId().equals(treeId)) {
- // No change. Do nothing.
- return rw.parseCommit(headId);
- }
-
- CommitBuilder commit = new CommitBuilder();
- commit.setTreeId(treeId);
- if (headId != null)
- commit.setParentIds(headId);
- commit.setAuthor(author);
- commit.setCommitter(author);
- commit.setMessage(RepoText.get().repoCommitMessage);
-
- ObjectId commitId = inserter.insert(commit);
- inserter.flush();
-
- RefUpdate ru = repo.updateRef(targetBranch);
- ru.setNewObjectId(commitId);
- ru.setExpectedOldObjectId(headId != null ? headId : ObjectId.zeroId());
- Result rc = ru.update(rw);
- switch (rc) {
- case NEW:
- case FORCED:
- case FAST_FORWARD:
- // Successful. Do nothing.
- break;
- case REJECTED:
- case LOCK_FAILURE:
- throw new ConcurrentRefUpdateException(MessageFormat
- .format(JGitText.get().cannotLock, targetBranch),
- ru.getRef(), rc);
- default:
- throw new JGitInternalException(MessageFormat.format(
- JGitText.get().updatingRefFailed,
- targetBranch, commitId.name(), rc));
- }
-
- return rw.parseCommit(commitId);
- }
-
- private void addSubmodule(String name, String url, String path,
- String revision, List<CopyFile> copyfiles, List<LinkFile> linkfiles,
- Git git) throws GitAPIException, IOException {
- assert (!repo.isBare());
- assert (git != null);
- if (!linkfiles.isEmpty()) {
- throw new UnsupportedOperationException(
- JGitText.get().nonBareLinkFilesNotSupported);
- }
-
- SubmoduleAddCommand add = git.submoduleAdd().setName(name).setPath(path)
- .setURI(url);
- if (monitor != null)
- add.setProgressMonitor(monitor);
-
- Repository subRepo = add.call();
- if (revision != null) {
- try (Git sub = new Git(subRepo)) {
- sub.checkout().setName(findRef(revision, subRepo)).call();
- }
- subRepo.close();
- git.add().addFilepattern(path).call();
- }
- for (CopyFile copyfile : copyfiles) {
- copyfile.copy();
- git.add().addFilepattern(copyfile.dest).call();
- }
+ RegularSuperprojectWriter writer = new RegularSuperprojectWriter(repo, monitor);
+ return writer.write(filteredProjects);
}
/**
@@ -910,13 +682,4 @@ static URI relativize(URI current, URI target) {
return URI.create(j.toString());
}
- private static String findRef(String ref, Repository repo)
- throws IOException {
- if (!ObjectId.isId(ref)) {
- Ref r = repo.exactRef(R_REMOTES + DEFAULT_REMOTE_NAME + "/" + ref); //$NON-NLS-1$
- if (r != null)
- return r.getName();
- }
- return ref;
- }
}
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 b8b1ae2..bf65dae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -384,6 +384,8 @@ public static JGitText get() {
/***/ public String inMemoryBufferLimitExceeded;
/***/ public String inputDidntMatchLength;
/***/ public String inputStreamMustSupportMark;
+ /***/ public String integerValueNotInRange;
+ /***/ public String integerValueNotInRangeSubSection;
/***/ public String integerValueOutOfRange;
/***/ public String internalRevisionError;
/***/ public String internalServerError;
@@ -395,6 +397,7 @@ public static JGitText get() {
/***/ public String invalidBooleanValue;
/***/ public String invalidChannel;
/***/ public String invalidCommitParentNumber;
+ /***/ public String invalidCoreAbbrev;
/***/ public String invalidDepth;
/***/ public String invalidEncoding;
/***/ public String invalidEncryption;
@@ -596,6 +599,11 @@ public static JGitText get() {
/***/ public String pushCertificateInvalidFieldValue;
/***/ public String pushCertificateInvalidHeader;
/***/ public String pushCertificateInvalidSignature;
+ /***/ public String pushDefaultNothing;
+ /***/ public String pushDefaultNoUpstream;
+ /***/ public String pushDefaultSimple;
+ /***/ public String pushDefaultTriangularUpstream;
+ /***/ public String pushDefaultUnknown;
/***/ public String pushIsNotSupportedForBundleTransport;
/***/ public String pushNotPermitted;
/***/ public String pushOptionsNotSupported;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java
new file mode 100644
index 0000000..509515c
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.diffmergetool;
+
+/**
+ * Pre-defined command line diff tools.
+ *
+ * Adds same diff tools as also pre-defined in C-Git
+ * <p>
+ * see "git-core\mergetools\"
+ * </p>
+ * <p>
+ * see links to command line parameter description for the tools
+ * </p>
+ *
+ * <pre>
+ * araxis
+ * bc
+ * bc3
+ * codecompare
+ * deltawalker
+ * diffmerge
+ * diffuse
+ * ecmerge
+ * emerge
+ * examdiff
+ * guiffy
+ * gvimdiff
+ * gvimdiff2
+ * gvimdiff3
+ * kdiff3
+ * kompare
+ * meld
+ * opendiff
+ * p4merge
+ * tkdiff
+ * vimdiff
+ * vimdiff2
+ * vimdiff3
+ * winmerge
+ * xxdiff
+ * </pre>
+ *
+ */
+@SuppressWarnings("nls")
+public enum CommandLineDiffTool {
+ /**
+ * See: <a href=
+ * "https://www.araxis.com/merge/documentation-windows/command-line.en">https://www.araxis.com/merge/documentation-windows/command-line.en</a>
+ */
+ araxis("compare", "-wait -2 \"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://www.scootersoftware.com/v4help/index.html?command_line_reference.html">https://www.scootersoftware.com/v4help/index.html?command_line_reference.html</a>
+ */
+ bc("bcomp", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://www.scootersoftware.com/v4help/index.html?command_line_reference.html">https://www.scootersoftware.com/v4help/index.html?command_line_reference.html</a>
+ */
+ bc3("bcompare", bc),
+ /**
+ * See: <a href=
+ * "https://www.devart.com/codecompare/docs/index.html?comparing_via_command_line.htm">https://www.devart.com/codecompare/docs/index.html?comparing_via_command_line.htm</a>
+ */
+ codecompare("CodeCompare", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://www.deltawalker.com/integrate/command-line">https://www.deltawalker.com/integrate/command-line</a>
+ */
+ deltawalker("DeltaWalker", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html">https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html</a>
+ */
+ diffmerge("diffmerge", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://diffuse.sourceforge.net/manual.html#introduction-usage">http://diffuse.sourceforge.net/manual.html#introduction-usage</a>
+ */
+ diffuse("diffuse", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://www.elliecomputing.com/en/OnlineDoc/ecmerge_en/44205167.asp">http://www.elliecomputing.com/en/OnlineDoc/ecmerge_en/44205167.asp</a>
+ */
+ ecmerge("ecmerge", "--default --mode=diff2 \"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://www.gnu.org/software/emacs/manual/html_node/emacs/Overview-of-Emerge.html">https://www.gnu.org/software/emacs/manual/html_node/emacs/Overview-of-Emerge.html</a>
+ */
+ emerge("emacs", "-f emerge-files-command \"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://www.prestosoft.com/ps.asp?page=htmlhelp/edp/command_line_options">https://www.prestosoft.com/ps.asp?page=htmlhelp/edp/command_line_options</a>
+ */
+ examdiff("ExamDiff", "\"$LOCAL\" \"$REMOTE\" -nh"),
+ /**
+ * See: <a href=
+ * "https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html">https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html</a>
+ */
+ guiffy("guiffy", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ gvimdiff("gviewdiff", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ gvimdiff2(gvimdiff),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ gvimdiff3(gvimdiff),
+ /**
+ * See: <a href=
+ * "http://kdiff3.sourceforge.net/doc/documentation.html">http://kdiff3.sourceforge.net/doc/documentation.html</a>
+ */
+ kdiff3("kdiff3",
+ "--L1 \"$MERGED (A)\" --L2 \"$MERGED (B)\" \"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://docs.kde.org/trunk5/en/kdesdk/kompare/commandline-options.html">https://docs.kde.org/trunk5/en/kdesdk/kompare/commandline-options.html</a>
+ */
+ kompare("kompare", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "ttp://meldmerge.org/help/file-mode.html">http://meldmerge.org/help/file-mode.html</a>
+ */
+ meld("meld", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://www.manpagez.com/man/1/opendiff/">http://www.manpagez.com/man/1/opendiff/</a>
+ * <p>
+ * Hint: check the ' | cat' for the call
+ * </p>
+ */
+ opendiff("opendiff", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "https://www.perforce.com/manuals/v15.1/cmdref/p4_merge.html">https://www.perforce.com/manuals/v15.1/cmdref/p4_merge.html</a>
+ */
+ p4merge("p4merge", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://linux.math.tifr.res.in/manuals/man/tkdiff.html">http://linux.math.tifr.res.in/manuals/man/tkdiff.html</a>
+ */
+ tkdiff("tkdiff", "\"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ vimdiff("viewdiff", gvimdiff),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ vimdiff2(vimdiff),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ vimdiff3(vimdiff),
+ /**
+ * See: <a href=
+ * "http://manual.winmerge.org/Command_line.html">http://manual.winmerge.org/Command_line.html</a>
+ * <p>
+ * Hint: check how 'mergetool_find_win32_cmd "WinMergeU.exe" "WinMerge"'
+ * works
+ * </p>
+ */
+ winmerge("WinMergeU", "-u -e \"$LOCAL\" \"$REMOTE\""),
+ /**
+ * See: <a href=
+ * "http://furius.ca/xxdiff/doc/xxdiff-doc.html">http://furius.ca/xxdiff/doc/xxdiff-doc.html</a>
+ */
+ xxdiff("xxdiff",
+ "-R 'Accel.Search: \"Ctrl+F\"' -R 'Accel.SearchForward: \"Ctrl+G\"' \"$LOCAL\" \"$REMOTE\"");
+
+ CommandLineDiffTool(String path, String parameters) {
+ this.path = path;
+ this.parameters = parameters;
+ }
+
+ CommandLineDiffTool(CommandLineDiffTool from) {
+ this(from.getPath(), from.getParameters());
+ }
+
+ CommandLineDiffTool(String path, CommandLineDiffTool from) {
+ this(path, from.getParameters());
+ }
+
+ private final String path;
+
+ private final String parameters;
+
+ /**
+ * @return path
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return parameters as one string
+ */
+ public String getParameters() {
+ return parameters;
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java
new file mode 100644
index 0000000..551f634
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.diffmergetool;
+
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+
+/**
+ * Keeps track of difftool related configuration options.
+ */
+public class DiffToolConfig {
+
+ /** Key for {@link Config#get(SectionParser)}. */
+ public static final Config.SectionParser<DiffToolConfig> KEY = DiffToolConfig::new;
+
+ private final String toolName;
+
+ private final String guiToolName;
+
+ private final boolean prompt;
+
+ private final BooleanTriState trustExitCode;
+
+ private final Map<String, ExternalDiffTool> tools;
+
+ private DiffToolConfig(Config rc) {
+ toolName = rc.getString(CONFIG_DIFF_SECTION, null, CONFIG_KEY_TOOL);
+ guiToolName = rc.getString(CONFIG_DIFF_SECTION, null,
+ CONFIG_KEY_GUITOOL);
+ prompt = rc.getBoolean(CONFIG_DIFFTOOL_SECTION, CONFIG_KEY_PROMPT,
+ true);
+ String trustStr = rc.getString(CONFIG_DIFFTOOL_SECTION, null,
+ CONFIG_KEY_TRUST_EXIT_CODE);
+ if (trustStr != null) {
+ trustExitCode = Boolean.parseBoolean(trustStr)
+ ? BooleanTriState.TRUE
+ : BooleanTriState.FALSE;
+ } else {
+ trustExitCode = BooleanTriState.UNSET;
+ }
+ tools = new HashMap<>();
+ Set<String> subsections = rc.getSubsections(CONFIG_DIFFTOOL_SECTION);
+ for (String name : subsections) {
+ String cmd = rc.getString(CONFIG_DIFFTOOL_SECTION, name,
+ CONFIG_KEY_CMD);
+ String path = rc.getString(CONFIG_DIFFTOOL_SECTION, name,
+ CONFIG_KEY_PATH);
+ if ((cmd != null) || (path != null)) {
+ tools.put(name, new UserDefinedDiffTool(name, path, cmd));
+ }
+ }
+ }
+
+ /**
+ * @return the default diff tool name (diff.tool)
+ */
+ public String getDefaultToolName() {
+ return toolName;
+ }
+
+ /**
+ * @return the default GUI diff tool name (diff.guitool)
+ */
+ public String getDefaultGuiToolName() {
+ return guiToolName;
+ }
+
+ /**
+ * @return the diff tool "prompt" option (difftool.prompt)
+ */
+ public boolean isPrompt() {
+ return prompt;
+ }
+
+ /**
+ * @return the diff tool "trust exit code" option (difftool.trustExitCode)
+ */
+ public boolean isTrustExitCode() {
+ return trustExitCode == BooleanTriState.TRUE;
+ }
+
+ /**
+ * @return the tools map
+ */
+ public Map<String, ExternalDiffTool> getTools() {
+ return tools;
+ }
+
+ /**
+ * @return the tool names
+ */
+ public Set<String> getToolNames() {
+ return tools.keySet();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
new file mode 100644
index 0000000..39729a4
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.diffmergetool;
+
+import java.util.TreeMap;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+
+/**
+ * Manages diff tools.
+ */
+public class DiffTools {
+
+ private final DiffToolConfig config;
+
+ private Map<String, ExternalDiffTool> predefinedTools;
+
+ private Map<String, ExternalDiffTool> userDefinedTools;
+
+ /**
+ * Creates the external diff-tools manager for given repository.
+ *
+ * @param repo
+ * the repository
+ */
+ public DiffTools(Repository repo) {
+ config = repo.getConfig().get(DiffToolConfig.KEY);
+ setupPredefinedTools();
+ setupUserDefinedTools();
+ }
+
+ /**
+ * Compare two versions of a file.
+ *
+ * @param newPath
+ * the new file path
+ * @param oldPath
+ * the old file path
+ * @param newId
+ * the new object ID
+ * @param oldId
+ * the old object ID
+ * @param toolName
+ * the selected tool name (can be null)
+ * @param prompt
+ * the prompt option
+ * @param gui
+ * the GUI option
+ * @param trustExitCode
+ * the "trust exit code" option
+ * @return the return code from executed tool
+ */
+ public int compare(String newPath, String oldPath, String newId,
+ String oldId, String toolName, BooleanTriState prompt,
+ BooleanTriState gui, BooleanTriState trustExitCode) {
+ return 0;
+ }
+
+ /**
+ * @return the tool names
+ */
+ public Set<String> getToolNames() {
+ return config.getToolNames();
+ }
+
+ /**
+ * @return the user defined tools
+ */
+ public Map<String, ExternalDiffTool> getUserDefinedTools() {
+ return Collections.unmodifiableMap(userDefinedTools);
+ }
+
+ /**
+ * @return the available predefined tools
+ */
+ public Map<String, ExternalDiffTool> getAvailableTools() {
+ return Collections.unmodifiableMap(predefinedTools);
+ }
+
+ /**
+ * @return the NOT available predefined tools
+ */
+ public Map<String, ExternalDiffTool> getNotAvailableTools() {
+ return Collections.unmodifiableMap(new TreeMap<>());
+ }
+
+ /**
+ * @param gui
+ * use the diff.guitool setting ?
+ * @return the default tool name
+ */
+ public String getDefaultToolName(BooleanTriState gui) {
+ return gui != BooleanTriState.UNSET ? "my_gui_tool" //$NON-NLS-1$
+ : "my_default_toolname"; //$NON-NLS-1$
+ }
+
+ /**
+ * @return is interactive (config prompt enabled) ?
+ */
+ public boolean isInteractive() {
+ return false;
+ }
+
+ private void setupPredefinedTools() {
+ predefinedTools = new TreeMap<>();
+ for (CommandLineDiffTool tool : CommandLineDiffTool.values()) {
+ predefinedTools.put(tool.name(), new PreDefinedDiffTool(tool));
+ }
+ }
+
+ private void setupUserDefinedTools() {
+ userDefinedTools = new TreeMap<>();
+ Map<String, ExternalDiffTool> userTools = config.getTools();
+ for (String name : userTools.keySet()) {
+ ExternalDiffTool userTool = userTools.get(name);
+ // if difftool.<name>.cmd is defined we have user defined tool
+ if (userTool.getCommand() != null) {
+ userDefinedTools.put(name, userTool);
+ } else if (userTool.getPath() != null) {
+ // if difftool.<name>.path is defined we just overload the path
+ // of predefined tool
+ PreDefinedDiffTool predefTool = (PreDefinedDiffTool) predefinedTools
+ .get(name);
+ if (predefTool != null) {
+ predefTool.setPath(userTool.getPath());
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalDiffTool.java
new file mode 100644
index 0000000..f2d7e82
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalDiffTool.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.diffmergetool;
+
+/**
+ * The external tool interface.
+ */
+public interface ExternalDiffTool {
+
+ /**
+ * @return the tool name
+ */
+ String getName();
+
+ /**
+ * @return the tool path
+ */
+ String getPath();
+
+ /**
+ * @return the tool command
+ */
+ String getCommand();
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java
new file mode 100644
index 0000000..1c69fb4
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.diffmergetool;
+
+/**
+ * The pre-defined diff tool.
+ */
+public class PreDefinedDiffTool extends UserDefinedDiffTool {
+
+ /**
+ * Create a pre-defined diff tool
+ *
+ * @param name
+ * the name
+ * @param path
+ * the path
+ * @param parameters
+ * the tool parameters as one string that is used together with
+ * path as command
+ */
+ public PreDefinedDiffTool(String name, String path, String parameters) {
+ super(name, path, parameters);
+ }
+
+ /**
+ * Creates the pre-defined diff tool
+ *
+ * @param tool
+ * the command line diff tool
+ *
+ */
+ public PreDefinedDiffTool(CommandLineDiffTool tool) {
+ this(tool.name(), tool.getPath(), tool.getParameters());
+ }
+
+ /**
+ * @param path
+ */
+ @Override
+ public void setPath(String path) {
+ // handling of spaces in path
+ if (path.contains(" ")) { //$NON-NLS-1$
+ // add quotes before if needed
+ if (!path.startsWith("\"")) { //$NON-NLS-1$
+ path = "\"" + path; //$NON-NLS-1$
+ }
+ // add quotes after if needed
+ if (!path.endsWith("\"")) { //$NON-NLS-1$
+ path = path + "\""; //$NON-NLS-1$
+ }
+ }
+ super.setPath(path);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the concatenated path and command of the pre-defined diff tool
+ */
+ @Override
+ public String getCommand() {
+ return getPath() + " " + super.getCommand(); //$NON-NLS-1$
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java
new file mode 100644
index 0000000..012296e
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.diffmergetool;
+
+/**
+ * The user-defined diff tool.
+ */
+public class UserDefinedDiffTool implements ExternalDiffTool {
+
+ /**
+ * the diff tool name
+ */
+ private final String name;
+
+ /**
+ * the diff tool path
+ */
+ private String path;
+
+ /**
+ * the diff tool command
+ */
+ private final String cmd;
+
+ /**
+ * Creates the diff tool
+ *
+ * @param name
+ * the name
+ * @param path
+ * the path
+ * @param cmd
+ * the command
+ */
+ public UserDefinedDiffTool(String name, String path, String cmd) {
+ this.name = name;
+ this.path = path;
+ this.cmd = cmd;
+ }
+
+ /**
+ * @return the diff tool name
+ */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * The path of the diff tool.
+ *
+ * <p>
+ * The path to a pre-defined external diff tool can be overridden by
+ * specifying {@code difftool.<tool>.path} in a configuration file.
+ * </p>
+ * <p>
+ * For a user defined diff tool (that does not override a pre-defined diff
+ * tool), the path is ignored when invoking the tool.
+ * </p>
+ *
+ * @return the diff tool path
+ *
+ * @see <a href=
+ * "https://git-scm.com/docs/git-difftool">https://git-scm.com/docs/git-difftool</a>
+ */
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * The command of the diff tool.
+ *
+ * <p>
+ * A pre-defined external diff tool can be overridden using the tools name
+ * in a configuration file. The overwritten tool is then a user defined tool
+ * and the command of the diff tool is specified with
+ * {@code difftool.<tool>.cmd}. This command must work without prepending
+ * the value of {@link #getPath()} and can sometimes include tool
+ * parameters.
+ * </p>
+ *
+ * @return the diff tool command
+ *
+ * @see <a href=
+ * "https://git-scm.com/docs/git-difftool">https://git-scm.com/docs/git-difftool</a>
+ */
+ @Override
+ public String getCommand() {
+ return cmd;
+ }
+
+ /**
+ * Overrides the path for the given tool. Equivalent to setting
+ * {@code difftool.<tool>.path}.
+ *
+ * @param path
+ * the new diff tool path
+ *
+ * @see <a href=
+ * "https://git-scm.com/docs/git-difftool">https://git-scm.com/docs/git-difftool</a>
+ */
+ public void setPath(String path) {
+ this.path = path;
+ }
+}
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 54c527c..b30d509 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
@@ -12,6 +12,10 @@
package org.eclipse.jgit.internal.storage.dfs;
import java.io.IOException;
+import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
@@ -166,6 +170,12 @@ public static DfsBlockCache getInstance() {
/** Limits of cache hot count per pack file extension. */
private final int[] cacheHotLimits = new int[PackExt.values().length];
+ /** Consumer of loading and eviction events of indexes. */
+ private final DfsBlockCacheConfig.IndexEventConsumer indexEventConsumer;
+
+ /** Stores timestamps of the last eviction of indexes. */
+ private final Map<EvictKey, Long> indexEvictionMap = new ConcurrentHashMap<>();
+
@SuppressWarnings("unchecked")
private DfsBlockCache(DfsBlockCacheConfig cfg) {
tableSize = tableSize(cfg);
@@ -213,6 +223,7 @@ private DfsBlockCache(DfsBlockCacheConfig cfg) {
cacheHotLimits[i] = DfsBlockCacheConfig.DEFAULT_CACHE_HOT_MAX;
}
}
+ indexEventConsumer = cfg.getIndexEventConsumer();
}
boolean shouldCopyThroughCache(long length) {
@@ -461,6 +472,7 @@ private void reserveSpace(long reserve, DfsStreamKey key) {
live -= dead.size;
getStat(liveBytes, dead.key).addAndGet(-dead.size);
getStat(statEvict, dead.key).incrementAndGet();
+ reportIndexEvicted(dead);
} while (maxBytes < live);
clockHand = prev;
}
@@ -515,11 +527,13 @@ void put(DfsBlock v) {
<T> Ref<T> getOrLoadRef(
DfsStreamKey key, long position, RefLoader<T> loader)
throws IOException {
+ long start = System.nanoTime();
int slot = slot(key, position);
HashEntry e1 = table.get(slot);
Ref<T> ref = scanRef(e1, key, position);
if (ref != null) {
getStat(statHit, key).incrementAndGet();
+ reportIndexRequested(ref, true /* cacheHit */, start);
return ref;
}
@@ -532,6 +546,8 @@ <T> Ref<T> getOrLoadRef(
ref = scanRef(e2, key, position);
if (ref != null) {
getStat(statHit, key).incrementAndGet();
+ reportIndexRequested(ref, true /* cacheHit */,
+ start);
return ref;
}
}
@@ -556,6 +572,7 @@ <T> Ref<T> getOrLoadRef(
} finally {
regionLock.unlock();
}
+ reportIndexRequested(ref, false /* cacheHit */, start);
return ref;
}
@@ -682,8 +699,9 @@ private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats,
}
private static HashEntry clean(HashEntry top) {
- while (top != null && top.ref.next == null)
+ while (top != null && top.ref.next == null) {
top = top.next;
+ }
if (top == null) {
return null;
}
@@ -691,6 +709,44 @@ private static HashEntry clean(HashEntry top) {
return n == top.next ? top : new HashEntry(n, top.ref);
}
+ private void reportIndexRequested(Ref<?> ref, boolean cacheHit,
+ long start) {
+ if (indexEventConsumer == null
+ || !isIndexOrBitmapExtPos(ref.key.packExtPos)) {
+ return;
+ }
+ EvictKey evictKey = new EvictKey(ref);
+ Long prevEvictedTime = indexEvictionMap.get(evictKey);
+ long now = System.nanoTime();
+ long sinceLastEvictionNanos = prevEvictedTime == null ? 0L
+ : now - prevEvictedTime.longValue();
+ indexEventConsumer.acceptRequestedEvent(ref.key.packExtPos, cacheHit,
+ (now - start) / 1000L /* micros */, ref.size,
+ Duration.ofNanos(sinceLastEvictionNanos));
+ }
+
+ private void reportIndexEvicted(Ref<?> dead) {
+ if (indexEventConsumer == null
+ || !indexEventConsumer.shouldReportEvictedEvent()
+ || !isIndexOrBitmapExtPos(dead.key.packExtPos)) {
+ return;
+ }
+ EvictKey evictKey = new EvictKey(dead);
+ Long prevEvictedTime = indexEvictionMap.get(evictKey);
+ long now = System.nanoTime();
+ long sinceLastEvictionNanos = prevEvictedTime == null ? 0L
+ : now - prevEvictedTime.longValue();
+ indexEvictionMap.put(evictKey, Long.valueOf(now));
+ indexEventConsumer.acceptEvictedEvent(dead.key.packExtPos, dead.size,
+ dead.totalHitCount.get(),
+ Duration.ofNanos(sinceLastEvictionNanos));
+ }
+
+ private static boolean isIndexOrBitmapExtPos(int packExtPos) {
+ return packExtPos == PackExt.INDEX.getPosition()
+ || packExtPos == PackExt.BITMAP_INDEX.getPosition();
+ }
+
private static final class HashEntry {
/** Next entry in the hash table's chain list. */
final HashEntry next;
@@ -712,6 +768,7 @@ static final class Ref<T> {
Ref next;
private volatile int hotCount;
+ private AtomicInteger totalHitCount = new AtomicInteger();
Ref(DfsStreamKey key, long position, long size, T v) {
this.key = key;
@@ -736,6 +793,7 @@ void markHotter() {
int cap = DfsBlockCache
.getInstance().cacheHotLimits[key.packExtPos];
hotCount = Math.min(cap, hotCount + 1);
+ totalHitCount.incrementAndGet();
}
void markColder() {
@@ -747,6 +805,34 @@ boolean isHot() {
}
}
+ private static final class EvictKey {
+ private final int keyHash;
+ private final int packExtPos;
+ private final long position;
+
+ EvictKey(Ref<?> ref) {
+ keyHash = ref.key.hash;
+ packExtPos = ref.key.packExtPos;
+ position = ref.position;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof EvictKey) {
+ EvictKey other = (EvictKey) object;
+ return keyHash == other.keyHash
+ && packExtPos == other.packExtPos
+ && position == other.position;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return DfsBlockCache.getInstance().hash(keyHash, position);
+ }
+ }
+
@FunctionalInterface
interface RefLoader<T> {
Ref<T> load() throws IOException;
@@ -763,4 +849,4 @@ interface ReadableChannelSupplier {
*/
ReadableChannel get() throws IOException;
}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
index 2716f79..69a3705 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
@@ -18,6 +18,7 @@
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO;
import java.text.MessageFormat;
+import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.function.Consumer;
@@ -46,9 +47,10 @@ public class DfsBlockCacheConfig {
private int concurrencyLevel;
private Consumer<Long> refLock;
-
private Map<PackExt, Integer> cacheHotMap;
+ private IndexEventConsumer indexEventConsumer;
+
/**
* Create a default configuration.
*/
@@ -216,6 +218,28 @@ public DfsBlockCacheConfig setCacheHotMap(
}
/**
+ * Get the consumer of cache index events.
+ *
+ * @return consumer of cache index events.
+ */
+ public IndexEventConsumer getIndexEventConsumer() {
+ return indexEventConsumer;
+ }
+
+ /**
+ * Set the consumer of cache index events.
+ *
+ * @param indexEventConsumer
+ * consumer of cache index events.
+ * @return {@code this}
+ */
+ public DfsBlockCacheConfig setIndexEventConsumer(
+ IndexEventConsumer indexEventConsumer) {
+ this.indexEventConsumer = indexEventConsumer;
+ return this;
+ }
+
+ /**
* Update properties by setting fields from the configuration.
* <p>
* If a property is not defined in the configuration, then it is left
@@ -272,4 +296,52 @@ public DfsBlockCacheConfig fromConfig(Config rc) {
}
return this;
}
-}
+
+ /** Consumer of DfsBlockCache loading and eviction events for indexes. */
+ public interface IndexEventConsumer {
+ /**
+ * Accept an event of an index requested. It could be loaded from either
+ * cache or storage.
+ *
+ * @param packExtPos
+ * position in {@code PackExt} enum
+ * @param cacheHit
+ * true if an index was already in cache. Otherwise, the
+ * index was loaded from storage into the cache in the
+ * current request,
+ * @param loadMicros
+ * time to load an index from cache or storage in
+ * microseconds
+ * @param bytes
+ * number of bytes loaded
+ * @param lastEvictionDuration
+ * time since last eviction, 0 if was not evicted yet
+ */
+ void acceptRequestedEvent(int packExtPos, boolean cacheHit,
+ long loadMicros, long bytes, Duration lastEvictionDuration);
+
+ /**
+ * Accept an event of an index evicted from cache.
+ *
+ * @param packExtPos
+ * position in {@code PackExt} enum
+ * @param bytes
+ * number of bytes evicted
+ * @param totalCacheHitCount
+ * number of times an index was accessed while in cache
+ * @param lastEvictionDuration
+ * time since last eviction, 0 if was not evicted yet
+ */
+ default void acceptEvictedEvent(int packExtPos, long bytes,
+ int totalCacheHitCount, Duration lastEvictionDuration) {
+ // Off by default.
+ }
+
+ /**
+ * @return true if reporting evicted events is enabled.
+ */
+ default boolean shouldReportEvictedEvent() {
+ return false;
+ }
+ }
+}
\ No newline at end of file
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 bb76df1..f7a2c94 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
@@ -1061,7 +1061,8 @@ private DfsBlockCache.Ref<PackBitmapIndex> loadBitmapIndex(DfsReader ctx,
}
in = new BufferedInputStream(in, bs);
bmidx = PackBitmapIndex.read(in, () -> idx(ctx),
- () -> getReverseIdx(ctx));
+ () -> getReverseIdx(ctx),
+ ctx.getOptions().shouldLoadRevIndexInParallel());
} finally {
size = rc.position();
ctx.stats.readBitmapIdxBytes += size;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
index 89de534..146f761 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
@@ -34,6 +34,8 @@ public class DfsReaderOptions {
private int streamPackBufferSize;
+ private boolean loadRevIndexInParallel;
+
/**
* Create a default reader configuration.
*/
@@ -113,6 +115,28 @@ public DfsReaderOptions setStreamPackBufferSize(int bufsz) {
}
/**
+ * Check if reverse index should be loaded in parallel.
+ *
+ * @return true if reverse index is loaded in parallel for bitmap index.
+ */
+ public boolean shouldLoadRevIndexInParallel() {
+ return loadRevIndexInParallel;
+ }
+
+ /**
+ * Enable (or disable) parallel loading of reverse index.
+ *
+ * @param loadRevIndexInParallel
+ * whether to load reverse index in parallel.
+ * @return {@code this}
+ */
+ public DfsReaderOptions setLoadRevIndexInParallel(
+ boolean loadRevIndexInParallel) {
+ this.loadRevIndexInParallel = loadRevIndexInParallel;
+ return this;
+ }
+
+ /**
* Update properties by setting fields from the configuration.
* <p>
* If a property is not defined in the configuration, then it is left
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 5b6894d..99da222 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
@@ -165,6 +165,15 @@ public void flush() {
}
};
}
+
+ @Override
+ public long getApproximateObjectCount() {
+ long count = 0;
+ for (DfsPackDescription p : packs) {
+ count += p.getObjectCount();
+ }
+ return count;
+ }
}
private static class MemPack extends DfsPackDescription {
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 b0612f9..cd4f168 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
@@ -73,7 +73,6 @@ public boolean isLarge() {
public ObjectStream openStream() throws MissingObjectException, IOException {
PackInputStream packIn;
// ctx is closed by PackInputStream, or explicitly in the finally block
- @SuppressWarnings("resource")
DfsReader ctx = db.newReader();
try {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
index 7dedeb5..094fdc1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/CachedObjectDirectory.java
@@ -263,4 +263,17 @@ private static class UnpackedObjectId extends ObjectIdOwnerMap.Entry {
private AlternateHandle.Id getAlternateId() {
return wrapped.getAlternateId();
}
+
+ @Override
+ public long getApproximateObjectCount() {
+ long count = 0;
+ for (Pack p : getPacks()) {
+ try {
+ count += p.getObjectCount();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+ return count;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
index f02c861..5152367 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
@@ -40,6 +40,7 @@
import org.eclipse.jgit.internal.storage.reftable.ReftableWriter;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.SystemReader;
/**
* A mutable stack of reftables on local filesystem storage. Not thread-safe.
@@ -527,11 +528,19 @@ boolean compactRange(int first, int last) throws IOException {
return false;
}
+ reload();
for (File f : deleteOnSuccess) {
- Files.delete(f.toPath());
+ try {
+ Files.delete(f.toPath());
+ } catch (IOException e) {
+ // Ignore: this can happen on Windows in case of concurrent processes.
+ // leave the garbage and continue.
+ if (!SystemReader.getInstance().isWindows()) {
+ throw e;
+ }
+ }
}
- reload();
return true;
} finally {
if (tmpTable != null) {
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 b371557..3e92cdd 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
@@ -672,18 +672,20 @@ void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException {
if (writeLogs) {
List<ReflogEntry> logs = oldDb.getReflogReader(r.getName())
- .getReverseEntries();
+ .getReverseEntries();
Collections.reverse(logs);
for (ReflogEntry e : logs) {
logWriter.log(r.getName(), e);
}
- }
+ }
}
try (RevWalk rw = new RevWalk(this)) {
bru.execute(rw, NullProgressMonitor.INSTANCE);
}
+ oldDb.close();
+
List<String> failed = new ArrayList<>();
for (ReceiveCommand cmd : bru.getCommands()) {
if (cmd.getResult() != ReceiveCommand.Result.OK) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
index 33621a1..b9af83d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
@@ -14,6 +14,7 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.StandardCopyOption;
@@ -24,6 +25,8 @@
import org.eclipse.jgit.internal.storage.file.FileObjectDatabase.InsertLooseObjectResult;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@@ -52,15 +55,22 @@ class LooseObjects {
private final UnpackedObjectCache unpackedObjectCache;
+ private final boolean trustFolderStat;
+
/**
* Initialize a reference to an on-disk object directory.
*
+ * @param config
+ * configuration for the loose objects handler.
* @param dir
* the location of the <code>objects</code> directory.
*/
- LooseObjects(File dir) {
+ LooseObjects(Config config, File dir) {
directory = dir;
unpackedObjectCache = new UnpackedObjectCache();
+ trustFolderStat = config.getBoolean(
+ ConfigConstants.CONFIG_CORE_SECTION,
+ ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
}
/**
@@ -98,6 +108,19 @@ boolean hasCached(AnyObjectId id) {
* @return {@code true} if the specified object is stored as a loose object.
*/
boolean has(AnyObjectId objectId) {
+ boolean exists = hasWithoutRefresh(objectId);
+ if (trustFolderStat || exists) {
+ return exists;
+ }
+ try (InputStream stream = Files.newInputStream(directory.toPath())) {
+ // refresh directory to work around NFS caching issue
+ } catch (IOException e) {
+ return false;
+ }
+ return hasWithoutRefresh(objectId);
+ }
+
+ private boolean hasWithoutRefresh(AnyObjectId objectId) {
return fileFor(objectId).exists();
}
@@ -183,6 +206,22 @@ ObjectLoader open(WindowCursor curs, AnyObjectId id) throws IOException {
*/
ObjectLoader getObjectLoader(WindowCursor curs, File path, AnyObjectId id)
throws IOException {
+ try {
+ return getObjectLoaderWithoutRefresh(curs, path, id);
+ } catch (FileNotFoundException e) {
+ if (trustFolderStat) {
+ throw e;
+ }
+ try (InputStream stream = Files
+ .newInputStream(directory.toPath())) {
+ // refresh directory to work around NFS caching issues
+ }
+ return getObjectLoaderWithoutRefresh(curs, path, id);
+ }
+ }
+
+ private ObjectLoader getObjectLoaderWithoutRefresh(WindowCursor curs,
+ File path, AnyObjectId id) throws IOException {
try (FileInputStream in = new FileInputStream(path)) {
unpackedObjectCache().add(id);
return UnpackedObject.open(in, path, id, curs);
@@ -203,16 +242,34 @@ UnpackedObjectCache unpackedObjectCache() {
}
long getSize(WindowCursor curs, AnyObjectId id) throws IOException {
+ try {
+ return getSizeWithoutRefresh(curs, id);
+ } catch (FileNotFoundException noFile) {
+ try {
+ if (trustFolderStat) {
+ throw noFile;
+ }
+ try (InputStream stream = Files
+ .newInputStream(directory.toPath())) {
+ // refresh directory to work around NFS caching issue
+ }
+ return getSizeWithoutRefresh(curs, id);
+ } catch (FileNotFoundException e) {
+ if (fileFor(id).exists()) {
+ throw noFile;
+ }
+ unpackedObjectCache().remove(id);
+ return -1;
+ }
+ }
+ }
+
+ private long getSizeWithoutRefresh(WindowCursor curs, AnyObjectId id)
+ throws IOException {
File f = fileFor(id);
try (FileInputStream in = new FileInputStream(f)) {
unpackedObjectCache().add(id);
return UnpackedObject.getSize(in, id, curs);
- } catch (FileNotFoundException noFile) {
- if (f.exists()) {
- throw noFile;
- }
- unpackedObjectCache().remove(id);
- return -1;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 627facc..531fd78 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -120,7 +120,7 @@ public ObjectDirectory(final Config cfg, final File dir,
File packDirectory = new File(objects, "pack"); //$NON-NLS-1$
File preservedDirectory = new File(packDirectory, "preserved"); //$NON-NLS-1$
alternatesFile = new File(objects, Constants.INFO_ALTERNATES);
- loose = new LooseObjects(objects);
+ loose = new LooseObjects(config, objects);
packed = new PackDirectory(config, packDirectory);
preserved = new PackDirectory(config, preservedDirectory);
this.fs = fs;
@@ -212,6 +212,20 @@ public Collection<Pack> getPacks() {
return packed.getPacks();
}
+ /** {@inheritDoc} */
+ @Override
+ public long getApproximateObjectCount() {
+ long count = 0;
+ for (Pack p : getPacks()) {
+ try {
+ count += p.getIndex().getObjectCount();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+ return count;
+ }
+
/**
* {@inheritDoc}
* <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
index 8401f07..8fb17fc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
@@ -95,7 +95,7 @@ public static PackBitmapIndex open(File idxFile, PackIndex packIndex,
*/
public static PackBitmapIndex read(InputStream fd, PackIndex packIndex,
PackReverseIndex reverseIndex) throws IOException {
- return new PackBitmapIndexV1(fd, () -> packIndex, () -> reverseIndex);
+ return new PackBitmapIndexV1(fd, packIndex, reverseIndex);
}
/**
@@ -114,6 +114,8 @@ public static PackBitmapIndex read(InputStream fd, PackIndex packIndex,
* @param reverseIndexSupplier
* the supplier for pack reverse index for the corresponding pack
* file.
+ * @param loadParallelRevIndex
+ * whether reverse index should be loaded in parallel
* @return a copy of the index in-memory.
* @throws java.io.IOException
* the stream cannot be read.
@@ -122,10 +124,11 @@ public static PackBitmapIndex read(InputStream fd, PackIndex packIndex,
*/
public static PackBitmapIndex read(InputStream fd,
SupplierWithIOException<PackIndex> packIndexSupplier,
- SupplierWithIOException<PackReverseIndex> reverseIndexSupplier)
+ SupplierWithIOException<PackReverseIndex> reverseIndexSupplier,
+ boolean loadParallelRevIndex)
throws IOException {
return new PackBitmapIndexV1(fd, packIndexSupplier,
- reverseIndexSupplier);
+ reverseIndexSupplier, loadParallelRevIndex);
}
/** Footer checksum applied on the bottom of the pack file. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
index 6846e3b..21aba3e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
@@ -17,6 +17,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.JGitText;
@@ -40,6 +46,23 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
private static final int MAX_XOR_OFFSET = 126;
+ private static final ExecutorService executor = Executors
+ .newCachedThreadPool(new ThreadFactory() {
+ private final ThreadFactory baseFactory = Executors
+ .defaultThreadFactory();
+
+ private final AtomicInteger threadNumber = new AtomicInteger(0);
+
+ @Override
+ public Thread newThread(Runnable runnable) {
+ Thread thread = baseFactory.newThread(runnable);
+ thread.setName("JGit-PackBitmapIndexV1-" //$NON-NLS-1$
+ + threadNumber.getAndIncrement());
+ thread.setDaemon(true);
+ return thread;
+ }
+ });
+
private final PackIndex packIndex;
private final PackReverseIndex reverseIndex;
private final EWAHCompressedBitmap commits;
@@ -49,15 +72,28 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
private final ObjectIdOwnerMap<StoredBitmap> bitmaps;
+ PackBitmapIndexV1(final InputStream fd, PackIndex packIndex,
+ PackReverseIndex reverseIndex) throws IOException {
+ this(fd, () -> packIndex, () -> reverseIndex, false);
+ }
+
PackBitmapIndexV1(final InputStream fd,
SupplierWithIOException<PackIndex> packIndexSupplier,
- SupplierWithIOException<PackReverseIndex> reverseIndexSupplier)
+ SupplierWithIOException<PackReverseIndex> reverseIndexSupplier,
+ boolean loadParallelRevIndex)
throws IOException {
// An entry is object id, xor offset, flag byte, and a length encoded
// bitmap. The object id is an int32 of the nth position sorted by name.
super(new ObjectIdOwnerMap<StoredBitmap>());
this.bitmaps = getBitmaps();
+ // Optionally start loading reverse index in parallel to loading bitmap
+ // from storage.
+ Future<PackReverseIndex> reverseIndexFuture = null;
+ if (loadParallelRevIndex) {
+ reverseIndexFuture = executor.submit(reverseIndexSupplier::get);
+ }
+
final byte[] scratch = new byte[32];
IO.readFully(fd, scratch, 0, scratch.length);
@@ -164,7 +200,18 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
bitmaps.add(sb);
}
- this.reverseIndex = reverseIndexSupplier.get();
+ PackReverseIndex computedReverseIndex;
+ if (loadParallelRevIndex && reverseIndexFuture != null) {
+ try {
+ computedReverseIndex = reverseIndexFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ // Fallback to loading reverse index through a supplier.
+ computedReverseIndex = reverseIndexSupplier.get();
+ }
+ } else {
+ computedReverseIndex = reverseIndexSupplier.get();
+ }
+ this.reverseIndex = computedReverseIndex;
}
/** {@inheritDoc} */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
index f32909f..a7f28c6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -63,12 +63,12 @@ class PackDirectory {
private static final PackList NO_PACKS = new PackList(FileSnapshot.DIRTY,
new Pack[0]);
- private final Config config;
-
private final File directory;
private final AtomicReference<PackList> packList;
+ private final boolean trustFolderStat;
+
/**
* Initialize a reference to an on-disk 'pack' directory.
*
@@ -78,9 +78,16 @@ class PackDirectory {
* the location of the {@code pack} directory.
*/
PackDirectory(Config config, File directory) {
- this.config = config;
this.directory = directory;
packList = new AtomicReference<>(NO_PACKS);
+
+ // Whether to trust the pack folder's modification time. If set to false
+ // we will always scan the .git/objects/pack folder to check for new
+ // pack files. If set to true (default) we use the folder's size,
+ // modification time, and key (inode) and assume that no new pack files
+ // can be in this folder if these attributes have not changed.
+ trustFolderStat = config.getBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
}
/**
@@ -331,16 +338,6 @@ private boolean doLogExponentialBackoff(int n) {
}
boolean searchPacksAgain(PackList old) {
- // Whether to trust the pack folder's modification time. If set
- // to false we will always scan the .git/objects/pack folder to
- // check for new pack files. If set to true (default) we use the
- // lastmodified attribute of the folder and assume that no new
- // pack files can be in this folder if his modification time has
- // not changed.
- boolean trustFolderStat = config.getBoolean(
- ConfigConstants.CONFIG_CORE_SECTION,
- ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
-
return ((!trustFolderStat) || old.snapshot.isModified(directory))
&& old != scanPacks(old);
}
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
index 9c1d33d..8b0ea4f 100644
--- 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
@@ -86,10 +86,16 @@
*/
class PackedBatchRefUpdate extends BatchRefUpdate {
private RefDirectory refdb;
+ private boolean shouldLockLooseRefs;
PackedBatchRefUpdate(RefDirectory refdb) {
- super(refdb);
- this.refdb = refdb;
+ this(refdb, true);
+ }
+
+ PackedBatchRefUpdate(RefDirectory refdb, boolean shouldLockLooseRefs) {
+ super(refdb);
+ this.refdb = refdb;
+ this.shouldLockLooseRefs = shouldLockLooseRefs;
}
/** {@inheritDoc} */
@@ -155,7 +161,7 @@ public void execute(RevWalk walk, ProgressMonitor monitor,
refdb.inProcessPackedRefsLock.lock();
try {
PackedRefList oldPackedList;
- if (!refdb.isInClone()) {
+ if (!refdb.isInClone() && shouldLockLooseRefs) {
locks = lockLooseRefs(pending);
if (locks == null) {
return;
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 07e3814..d4ad190 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
@@ -30,6 +30,7 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.nio.file.DirectoryNotEmptyException;
@@ -60,6 +61,7 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.TrustPackedRefsStat;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
@@ -177,6 +179,10 @@ public class RefDirectory extends RefDatabase {
private List<Integer> retrySleepMs = RETRY_SLEEP_MS;
+ private final boolean trustFolderStat;
+
+ private final TrustPackedRefsStat trustPackedRefsStat;
+
RefDirectory(FileRepository db) {
final FS fs = db.getFS();
parent = db;
@@ -188,6 +194,13 @@ public class RefDirectory extends RefDatabase {
looseRefs.set(RefList.<LooseRef> emptyList());
packedRefs.set(NO_PACKED_REFS);
+ trustFolderStat = db.getConfig()
+ .getBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
+ trustPackedRefsStat = db.getConfig()
+ .getEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT,
+ TrustPackedRefsStat.UNSET);
}
Repository getRepository() {
@@ -587,6 +600,21 @@ public PackedBatchRefUpdate newBatchUpdate() {
return new PackedBatchRefUpdate(this);
}
+ /**
+ * Create a new batch update to attempt on this database.
+ *
+ * @param shouldLockLooseRefs
+ * whether loose refs should be locked during the batch ref
+ * update. Note that this should only be set to {@code false} if
+ * the application using this ensures that no other ref updates
+ * run concurrently to avoid lost updates caused by a race. In
+ * such cases it can improve performance.
+ * @return a new batch update object
+ */
+ public PackedBatchRefUpdate newBatchUpdate(boolean shouldLockLooseRefs) {
+ return new PackedBatchRefUpdate(this, shouldLockLooseRefs);
+ }
+
/** {@inheritDoc} */
@Override
public boolean performsAtomicTransactions() {
@@ -874,13 +902,30 @@ else if (0 <= (idx = packed.find(dst.getName())))
}
PackedRefList getPackedRefs() throws IOException {
- boolean trustFolderStat = getRepository().getConfig().getBoolean(
- ConfigConstants.CONFIG_CORE_SECTION,
- ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
-
final PackedRefList curList = packedRefs.get();
- if (trustFolderStat && !curList.snapshot.isModified(packedRefsFile)) {
- return curList;
+
+ switch (trustPackedRefsStat) {
+ case NEVER:
+ break;
+ case AFTER_OPEN:
+ try (InputStream stream = Files
+ .newInputStream(packedRefsFile.toPath())) {
+ // open the file to refresh attributes (on some NFS clients)
+ } catch (FileNotFoundException e) {
+ // Ignore as packed-refs may not exist
+ }
+ //$FALL-THROUGH$
+ case ALWAYS:
+ if (!curList.snapshot.isModified(packedRefsFile)) {
+ return curList;
+ }
+ break;
+ case UNSET:
+ if (trustFolderStat
+ && !curList.snapshot.isModified(packedRefsFile)) {
+ return curList;
+ }
+ break;
}
final PackedRefList newList = readPackedRefs();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/CancellableDigestOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/CancellableDigestOutputStream.java
new file mode 100644
index 0000000..ca2095f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/io/CancellableDigestOutputStream.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022, Tencent.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.storage.io;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ProgressMonitor;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+
+/**
+ * An OutputStream that keeps a digest and checks every N bytes for
+ * cancellation.
+ */
+public class CancellableDigestOutputStream extends OutputStream {
+
+ /** The OutputStream checks every this value for cancellation **/
+ public static final int BYTES_TO_WRITE_BEFORE_CANCEL_CHECK = 128 * 1024;
+
+ private final ProgressMonitor writeMonitor;
+
+ private final OutputStream out;
+
+ private final MessageDigest md = Constants.newMessageDigest();
+
+ private long count;
+
+ private long checkCancelAt;
+
+ /**
+ * Initialize a CancellableDigestOutputStream.
+ *
+ * @param writeMonitor
+ * monitor to update on output progress and check cancel.
+ * @param out
+ * target stream to receive all contents.
+ */
+ public CancellableDigestOutputStream(ProgressMonitor writeMonitor,
+ OutputStream out) {
+ this.writeMonitor = writeMonitor;
+ this.out = out;
+ this.checkCancelAt = BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
+ }
+
+ /**
+ * Get the monitor which is used to update on output progress and check
+ * cancel.
+ *
+ * @return the monitor
+ */
+ public final ProgressMonitor getWriteMonitor() {
+ return writeMonitor;
+ }
+
+ /**
+ * Obtain the current SHA-1 digest.
+ *
+ * @return SHA-1 digest
+ */
+ public final byte[] getDigest() {
+ return md.digest();
+ }
+
+ /**
+ * Get total number of bytes written since stream start.
+ *
+ * @return total number of bytes written since stream start.
+ */
+ public final long length() {
+ return count;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void write(int b) throws IOException {
+ if (checkCancelAt <= count) {
+ if (writeMonitor.isCancelled()) {
+ throw new InterruptedIOException();
+ }
+ checkCancelAt = count + BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
+ }
+
+ out.write(b);
+ md.update((byte) b);
+ count++;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void write(byte[] b, int off, int len) throws IOException {
+ while (0 < len) {
+ if (checkCancelAt <= count) {
+ if (writeMonitor.isCancelled()) {
+ throw new InterruptedIOException();
+ }
+ checkCancelAt = count + BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
+ }
+
+ int n = Math.min(len, BYTES_TO_WRITE_BEFORE_CANCEL_CHECK);
+ out.write(b, off, n);
+ md.update(b, off, n);
+ count += n;
+
+ off += n;
+ len -= n;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void flush() throws IOException {
+ out.flush();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
index 7104b94..2d0fe28 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java
@@ -17,10 +17,8 @@
import java.io.IOException;
import java.io.OutputStream;
-import java.security.MessageDigest;
-import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.internal.storage.io.CancellableDigestOutputStream;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.util.NB;
@@ -28,25 +26,14 @@
* Custom output stream to support
* {@link org.eclipse.jgit.internal.storage.pack.PackWriter}.
*/
-public final class PackOutputStream extends OutputStream {
- private static final int BYTES_TO_WRITE_BEFORE_CANCEL_CHECK = 128 * 1024;
-
- private final ProgressMonitor writeMonitor;
-
- private final OutputStream out;
+public final class PackOutputStream extends CancellableDigestOutputStream {
private final PackWriter packWriter;
- private final MessageDigest md = Constants.newMessageDigest();
-
- private long count;
-
private final byte[] headerBuffer = new byte[32];
private final byte[] copyBuffer = new byte[64 << 10];
- private long checkCancelAt;
-
private boolean ofsDelta;
/**
@@ -66,48 +53,8 @@ public final class PackOutputStream extends OutputStream {
*/
public PackOutputStream(final ProgressMonitor writeMonitor,
final OutputStream out, final PackWriter pw) {
- this.writeMonitor = writeMonitor;
- this.out = out;
+ super(writeMonitor, out);
this.packWriter = pw;
- this.checkCancelAt = BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
- }
-
- /** {@inheritDoc} */
- @Override
- public final void write(int b) throws IOException {
- count++;
- out.write(b);
- md.update((byte) b);
- }
-
- /** {@inheritDoc} */
- @Override
- public final void write(byte[] b, int off, int len)
- throws IOException {
- while (0 < len) {
- final int n = Math.min(len, BYTES_TO_WRITE_BEFORE_CANCEL_CHECK);
- count += n;
-
- if (checkCancelAt <= count) {
- if (writeMonitor.isCancelled()) {
- throw new IOException(
- JGitText.get().packingCancelledDuringObjectsWriting);
- }
- checkCancelAt = count + BYTES_TO_WRITE_BEFORE_CANCEL_CHECK;
- }
-
- out.write(b, off, n);
- md.update(b, off, n);
-
- off += n;
- len -= n;
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void flush() throws IOException {
- out.flush();
}
final void writeFileHeader(int version, long objectCount)
@@ -160,7 +107,7 @@ public final void writeHeader(ObjectToPack otp, long rawLength)
ObjectToPack b = otp.getDeltaBase();
if (b != null && (b.isWritten() & ofsDelta)) { // Non-short-circuit logic is intentional
int n = objectHeader(rawLength, OBJ_OFS_DELTA, headerBuffer);
- n = ofsDelta(count - b.getOffset(), headerBuffer, n);
+ n = ofsDelta(length() - b.getOffset(), headerBuffer, n);
write(headerBuffer, 0, n);
} else if (otp.isDeltaRepresentation()) {
int n = objectHeader(rawLength, OBJ_REF_DELTA, headerBuffer);
@@ -209,20 +156,6 @@ private static final int ofsDeltaVarIntLength(long v) {
}
void endObject() {
- writeMonitor.update(1);
- }
-
- /**
- * Get total number of bytes written since stream start.
- *
- * @return total number of bytes written since stream start.
- */
- public final long length() {
- return count;
- }
-
- /** @return obtain the current SHA-1 digest. */
- final byte[] getDigest() {
- return md.digest();
+ getWriteMonitor().update(1);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java
index 648d4a1..659ccb8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java
@@ -502,6 +502,98 @@ public static boolean flag(String value) {
}
/**
+ * Converts an OpenSSH time value into a number of seconds. The format is
+ * defined by OpenSSH as a sequence of (positive) integers with suffixes for
+ * seconds, minutes, hours, days, and weeks.
+ *
+ * @param value
+ * to convert
+ * @return the parsed value as a number of seconds, or -1 if the value is
+ * not a valid OpenSSH time value
+ * @see <a href="https://man.openbsd.org/sshd_config.5#TIME_FORMATS">OpenBSD
+ * man 5 sshd_config, section TIME FORMATS</a>
+ */
+ public static int timeSpec(String value) {
+ if (value == null) {
+ return -1;
+ }
+ try {
+ int length = value.length();
+ int i = 0;
+ int seconds = 0;
+ boolean valueSeen = false;
+ while (i < length) {
+ // Skip whitespace
+ char ch = value.charAt(i);
+ if (Character.isWhitespace(ch)) {
+ i++;
+ continue;
+ }
+ if (ch == '+') {
+ // OpenSSH uses strtol with base 10: a leading plus sign is
+ // allowed.
+ i++;
+ }
+ int val = 0;
+ int j = i;
+ while (j < length) {
+ ch = value.charAt(j++);
+ if (ch >= '0' && ch <= '9') {
+ val = Math.addExact(Math.multiplyExact(val, 10),
+ ch - '0');
+ } else {
+ j--;
+ break;
+ }
+ }
+ if (i == j) {
+ // No digits seen
+ return -1;
+ }
+ i = j;
+ int multiplier = 1;
+ if (i < length) {
+ ch = value.charAt(i++);
+ switch (ch) {
+ case 's':
+ case 'S':
+ break;
+ case 'm':
+ case 'M':
+ multiplier = 60;
+ break;
+ case 'h':
+ case 'H':
+ multiplier = 3600;
+ break;
+ case 'd':
+ case 'D':
+ multiplier = 24 * 3600;
+ break;
+ case 'w':
+ case 'W':
+ multiplier = 7 * 24 * 3600;
+ break;
+ default:
+ if (Character.isWhitespace(ch)) {
+ break;
+ }
+ // Invalid time spec
+ return -1;
+ }
+ }
+ seconds = Math.addExact(seconds,
+ Math.multiplyExact(val, multiplier));
+ valueSeen = true;
+ }
+ return valueSeen ? seconds : -1;
+ } catch (ArithmeticException e) {
+ // Overflow
+ return -1;
+ }
+ }
+
+ /**
* Retrieves the local user name as given in the constructor.
*
* @return the user name
@@ -549,6 +641,7 @@ public static class HostEntry implements SshConfigStore.HostConfig {
LIST_KEYS.add(SshConstants.GLOBAL_KNOWN_HOSTS_FILE);
LIST_KEYS.add(SshConstants.SEND_ENV);
LIST_KEYS.add(SshConstants.USER_KNOWN_HOSTS_FILE);
+ LIST_KEYS.add(SshConstants.ADD_KEYS_TO_AGENT); // confirm timeSpec
}
/**
@@ -871,7 +964,8 @@ void substitute(String originalHostName, int port, String userName,
if (options != null) {
// HOSTNAME already done above
String value = options.get(SshConstants.IDENTITY_AGENT);
- if (value != null) {
+ if (value != null && !SshConstants.NONE.equals(value)
+ && !SshConstants.ENV_SSH_AUTH_SOCKET.equals(value)) {
value = r.substitute(value, Replacer.DEFAULT_TOKENS, true);
value = toFile(value, home).getPath();
options.put(SshConstants.IDENTITY_AGENT, value);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java
new file mode 100644
index 0000000..9109cfd
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+import static org.eclipse.jgit.lib.TypedConfigGetter.UNSET_INT;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.api.errors.InvalidConfigurationException;
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * Git configuration option <a
+ * href=https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreabbrev">
+ * core.abbrev</a>
+ *
+ * @since 6.1
+ */
+public final class AbbrevConfig {
+ private static final String VALUE_NO = "no"; //$NON-NLS-1$
+
+ private static final String VALUE_AUTO = "auto"; //$NON-NLS-1$
+
+ /**
+ * The minimum value of abbrev
+ */
+ public static final int MIN_ABBREV = 4;
+
+ /**
+ * Cap configured core.abbrev to range between minimum of 4 and number of
+ * hex-digits of a full object id.
+ *
+ * @param len
+ * configured number of hex-digits to abbreviate object ids to
+ * @return core.abbrev capped to range between minimum of 4 and number of
+ * hex-digits of a full object id
+ */
+ public static int capAbbrev(int len) {
+ return Math.min(Math.max(MIN_ABBREV, len),
+ Constants.OBJECT_ID_STRING_LENGTH);
+ }
+
+ /**
+ * No abbreviation
+ */
+ public final static AbbrevConfig NO = new AbbrevConfig(
+ Constants.OBJECT_ID_STRING_LENGTH);
+
+ /**
+ * Parse string value of core.abbrev git option for a given repository
+ *
+ * @param repo
+ * repository
+ * @return the parsed AbbrevConfig
+ * @throws InvalidConfigurationException
+ * if value of core.abbrev is invalid
+ */
+ public static AbbrevConfig parseFromConfig(Repository repo)
+ throws InvalidConfigurationException {
+ Config config = repo.getConfig();
+ String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_ABBREV);
+ if (value == null || value.equalsIgnoreCase(VALUE_AUTO)) {
+ return auto(repo);
+ }
+ if (value.equalsIgnoreCase(VALUE_NO)) {
+ return NO;
+ }
+ try {
+ int len = config.getIntInRange(ConfigConstants.CONFIG_CORE_SECTION,
+ ConfigConstants.CONFIG_KEY_ABBREV, MIN_ABBREV,
+ Constants.OBJECT_ID_STRING_LENGTH, UNSET_INT);
+ if (len == UNSET_INT) {
+ // Unset was checked above. If we get UNSET_INT here, then
+ // either the value was UNSET_INT, or it was an invalid value
+ // (not an integer, or out of range), and EGit's
+ // ReportingTypedGetter caught the exception and has logged a
+ // warning. In either case we should fall back to some sane
+ // default.
+ len = OBJECT_ID_ABBREV_STRING_LENGTH;
+ }
+ return new AbbrevConfig(len);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidConfigurationException(MessageFormat
+ .format(JGitText.get().invalidCoreAbbrev, value), e);
+ }
+ }
+
+ /**
+ * An appropriate value is computed based on the approximate number of
+ * packed objects in a repository, which hopefully is enough for abbreviated
+ * object names to stay unique for some time.
+ *
+ * @param repo
+ * @return appropriate value computed based on the approximate number of
+ * packed objects in a repository
+ */
+ private static AbbrevConfig auto(Repository repo) {
+ long count = repo.getObjectDatabase().getApproximateObjectCount();
+ if (count == -1) {
+ return new AbbrevConfig(OBJECT_ID_ABBREV_STRING_LENGTH);
+ }
+ // find msb, round to next power of 2
+ int len = 63 - Long.numberOfLeadingZeros(count) + 1;
+ // With the order of 2^len objects, we expect a collision at
+ // 2^(len/2). But we also care about hex chars, not bits, and
+ // there are 4 bits per hex. So all together we need to divide
+ // by 2; but we also want to round odd numbers up, hence adding
+ // one before dividing.
+ len = (len + 1) / 2;
+ // for small repos use at least fallback length
+ return new AbbrevConfig(Math.max(len, OBJECT_ID_ABBREV_STRING_LENGTH));
+ }
+
+ /**
+ * All other possible abbreviation lengths. Valid range 4 to number of
+ * hex-digits of an unabbreviated object id (40 for SHA1 object ids, jgit
+ * doesn't support SHA256 yet).
+ */
+ private int abbrev;
+
+ /**
+ * @param abbrev
+ */
+ private AbbrevConfig(int abbrev) {
+ this.abbrev = capAbbrev(abbrev);
+ }
+
+ /**
+ * Get the configured abbreviation length for object ids.
+ *
+ * @return the configured abbreviation length for object ids
+ */
+ public int get() {
+ return abbrev;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(abbrev);
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
index 6da6f12..aa613d0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
@@ -138,6 +138,18 @@ public String getRemote() {
}
/**
+ * Get the remote this branch is configured to push to.
+ *
+ * @return the remote this branch is configured to push to, or {@code null}
+ * if not defined
+ * @since 6.1
+ */
+ public String getPushRemote() {
+ return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
+ branchName, ConfigConstants.CONFIG_KEY_PUSH_REMOTE);
+ }
+
+ /**
* Get the name of the upstream branch as it is called on the remote
*
* @return the name of the upstream branch as it is called on the remote, or
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
index 22e1f98..55cc026 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
@@ -18,11 +18,13 @@
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.text.MessageFormat;
+import java.util.Locale;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Config.ConfigEnum;
import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
@@ -34,22 +36,76 @@
* @since 5.13
*/
public class CommitConfig {
+
/**
* Key for {@link Config#get(SectionParser)}.
*/
public static final Config.SectionParser<CommitConfig> KEY = CommitConfig::new;
+ private static final String CUT = " ------------------------ >8 ------------------------\n"; //$NON-NLS-1$
+
+ /**
+ * How to clean up commit messages when committing.
+ *
+ * @since 6.1
+ */
+ public enum CleanupMode implements ConfigEnum {
+
+ /**
+ * {@link #WHITESPACE}, additionally remove comment lines.
+ */
+ STRIP,
+
+ /**
+ * Remove trailing whitespace and leading and trailing empty lines;
+ * collapse multiple empty lines to a single one.
+ */
+ WHITESPACE,
+
+ /**
+ * Make no changes.
+ */
+ VERBATIM,
+
+ /**
+ * Omit everything from the first "scissor" line on, then apply
+ * {@link #WHITESPACE}.
+ */
+ SCISSORS,
+
+ /**
+ * Use {@link #STRIP} for user-edited messages, otherwise
+ * {@link #WHITESPACE}, unless overridden by a git config setting other
+ * than DEFAULT.
+ */
+ DEFAULT;
+
+ @Override
+ public String toConfigValue() {
+ return name().toLowerCase(Locale.ROOT);
+ }
+
+ @Override
+ public boolean matchConfigValue(String in) {
+ return toConfigValue().equals(in);
+ }
+ }
+
private final static Charset DEFAULT_COMMIT_MESSAGE_ENCODING = StandardCharsets.UTF_8;
private String i18nCommitEncoding;
private String commitTemplatePath;
+ private CleanupMode cleanupMode;
+
private CommitConfig(Config rc) {
commitTemplatePath = rc.getString(ConfigConstants.CONFIG_COMMIT_SECTION,
null, ConfigConstants.CONFIG_KEY_COMMIT_TEMPLATE);
i18nCommitEncoding = rc.getString(ConfigConstants.CONFIG_SECTION_I18N,
null, ConfigConstants.CONFIG_KEY_COMMIT_ENCODING);
+ cleanupMode = rc.getEnum(ConfigConstants.CONFIG_COMMIT_SECTION, null,
+ ConfigConstants.CONFIG_KEY_CLEANUP, CleanupMode.DEFAULT);
}
/**
@@ -75,6 +131,48 @@ public String getCommitEncoding() {
}
/**
+ * Retrieves the {@link CleanupMode} as given by git config
+ * {@code commit.cleanup}.
+ *
+ * @return the {@link CleanupMode}; {@link CleanupMode#DEFAULT} if the git
+ * config is not set
+ * @since 6.1
+ */
+ @NonNull
+ public CleanupMode getCleanupMode() {
+ return cleanupMode;
+ }
+
+ /**
+ * Computes a non-default {@link CleanupMode} from the given mode and the
+ * git config.
+ *
+ * @param mode
+ * {@link CleanupMode} to resolve
+ * @param defaultStrip
+ * if {@code true} return {@link CleanupMode#STRIP} if the git
+ * config is also "default", otherwise return
+ * {@link CleanupMode#WHITESPACE}
+ * @return the {@code mode}, if it is not {@link CleanupMode#DEFAULT},
+ * otherwise the resolved mode, which is never
+ * {@link CleanupMode#DEFAULT}
+ * @since 6.1
+ */
+ @NonNull
+ public CleanupMode resolve(@NonNull CleanupMode mode,
+ boolean defaultStrip) {
+ if (CleanupMode.DEFAULT == mode) {
+ CleanupMode defaultMode = getCleanupMode();
+ if (CleanupMode.DEFAULT == defaultMode) {
+ return defaultStrip ? CleanupMode.STRIP
+ : CleanupMode.WHITESPACE;
+ }
+ return defaultMode;
+ }
+ return mode;
+ }
+
+ /**
* Get the content to the commit template as defined in
* {@code commit.template}. If no {@code i18n.commitEncoding} is specified,
* UTF-8 fallback is used.
@@ -135,4 +233,86 @@ private Charset getEncoding() throws ConfigInvalidException {
return commitMessageEncoding;
}
+
+ /**
+ * Processes a text according to the given {@link CleanupMode}.
+ *
+ * @param text
+ * text to process
+ * @param mode
+ * {@link CleanupMode} to use
+ * @param commentChar
+ * comment character (normally {@code #}) to use if {@code mode}
+ * is {@link CleanupMode#STRIP} or {@link CleanupMode#SCISSORS}
+ * @return the processed text
+ * @throws IllegalArgumentException
+ * if {@code mode} is {@link CleanupMode#DEFAULT} (use
+ * {@link #resolve(CleanupMode, boolean)} first)
+ * @since 6.1
+ */
+ public static String cleanText(@NonNull String text,
+ @NonNull CleanupMode mode, char commentChar) {
+ String toProcess = text;
+ boolean strip = false;
+ switch (mode) {
+ case VERBATIM:
+ return text;
+ case SCISSORS:
+ String cut = commentChar + CUT;
+ if (text.startsWith(cut)) {
+ return ""; //$NON-NLS-1$
+ }
+ int cutPos = text.indexOf('\n' + cut);
+ if (cutPos >= 0) {
+ toProcess = text.substring(0, cutPos + 1);
+ }
+ break;
+ case STRIP:
+ strip = true;
+ break;
+ case WHITESPACE:
+ break;
+ case DEFAULT:
+ default:
+ // Internal error; no translation
+ throw new IllegalArgumentException("Invalid clean-up mode " + mode); //$NON-NLS-1$
+ }
+ // WHITESPACE
+ StringBuilder result = new StringBuilder();
+ boolean lastWasEmpty = true;
+ for (String line : toProcess.split("\n")) { //$NON-NLS-1$
+ line = line.stripTrailing();
+ if (line.isEmpty()) {
+ if (!lastWasEmpty) {
+ result.append('\n');
+ lastWasEmpty = true;
+ }
+ } else if (!strip || !isComment(line, commentChar)) {
+ lastWasEmpty = false;
+ result.append(line).append('\n');
+ }
+ }
+ int bufferSize = result.length();
+ if (lastWasEmpty && bufferSize > 0) {
+ bufferSize--;
+ result.setLength(bufferSize);
+ }
+ if (bufferSize > 0 && !toProcess.endsWith("\n")) { //$NON-NLS-1$
+ if (result.charAt(bufferSize - 1) == '\n') {
+ result.setLength(bufferSize - 1);
+ }
+ }
+ return result.toString();
+ }
+
+ private static boolean isComment(String text, char commentChar) {
+ int len = text.length();
+ for (int i = 0; i < len; i++) {
+ char ch = text.charAt(i);
+ if (!Character.isWhitespace(ch)) {
+ return ch == commentChar;
+ }
+ }
+ return false;
+ }
}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
index 1ce3e31..d1d66d2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -278,6 +278,54 @@ public int getInt(final String section, String subsection,
}
/**
+ * Obtain an integer value from the configuration which must be inside given
+ * range.
+ *
+ * @param section
+ * section the key is grouped within.
+ * @param name
+ * name of the key to get.
+ * @param minValue
+ * minimum value
+ * @param maxValue
+ * maximum value
+ * @param defaultValue
+ * default value to return if no value was present.
+ * @return an integer value from the configuration, or defaultValue.
+ * @since 6.1
+ */
+ public int getIntInRange(String section, String name, int minValue,
+ int maxValue, int defaultValue) {
+ return typedGetter.getIntInRange(this, section, null, name, minValue,
+ maxValue, defaultValue);
+ }
+
+ /**
+ * Obtain an integer value from the configuration which must be inside given
+ * range.
+ *
+ * @param section
+ * section the key is grouped within.
+ * @param subsection
+ * subsection name, such a remote or branch name.
+ * @param name
+ * name of the key to get.
+ * @param minValue
+ * minimum value
+ * @param maxValue
+ * maximum value
+ * @param defaultValue
+ * default value to return if no value was present.
+ * @return an integer value from the configuration, or defaultValue.
+ * @since 6.1
+ */
+ public int getIntInRange(String section, String subsection, String name,
+ int minValue, int maxValue, int defaultValue) {
+ return typedGetter.getIntInRange(this, section, subsection, name,
+ minValue, maxValue, defaultValue);
+ }
+
+ /**
* Obtain an integer value from the configuration.
*
* @param section
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 6f76326..4755693 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
- * Copyright (C) 2012, 2020, Robin Rosenberg and others
+ * Copyright (C) 2012-2013, Robin Rosenberg
+ * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -29,6 +30,48 @@ public final class ConfigConstants {
/** The "diff" section */
public static final String CONFIG_DIFF_SECTION = "diff";
+ /**
+ * The "tool" key within "diff" section
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_TOOL = "tool";
+
+ /**
+ * The "guitool" key within "diff" section
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_GUITOOL = "guitool";
+
+ /**
+ * The "difftool" section
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_DIFFTOOL_SECTION = "difftool";
+
+ /**
+ * The "prompt" key within "difftool" section
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_PROMPT = "prompt";
+
+ /**
+ * The "trustExitCode" key within "difftool" section
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_TRUST_EXIT_CODE = "trustExitCode";
+
+ /**
+ * The "cmd" key within "difftool.*." section
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_CMD = "cmd";
+
/** The "dfs" section */
public static final String CONFIG_DFS_SECTION = "dfs";
@@ -139,6 +182,13 @@ public final class ConfigConstants {
public static final String CONFIG_TAG_SECTION = "tag";
/**
+ * The "cleanup" key
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_CLEANUP = "cleanup";
+
+ /**
* The "gpgSign" key
*
* @since 5.2
@@ -279,6 +329,20 @@ public final class ConfigConstants {
/** The "remote" key */
public static final String CONFIG_KEY_REMOTE = "remote";
+ /**
+ * The "pushRemote" key.
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_PUSH_REMOTE = "pushRemote";
+
+ /**
+ * The "pushDefault" key.
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_PUSH_DEFAULT = "pushDefault";
+
/** The "merge" key */
public static final String CONFIG_KEY_MERGE = "merge";
@@ -771,4 +835,31 @@ public final class ConfigConstants {
*/
public static final String CONFIG_KEY_SEARCH_FOR_REUSE_TIMEOUT = "searchforreusetimeout";
+ /**
+ * The "push" section.
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_PUSH_SECTION = "push";
+
+ /**
+ * The "default" key.
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_DEFAULT = "default";
+
+ /**
+ * The "abbrev" key
+ *
+ * @since 6.1
+ */
+ public static final String CONFIG_KEY_ABBREV = "abbrev";
+
+ /**
+ * The "trustPackedRefsStat" key
+ *
+ * @since 6.1.1
+ */
+ public static final String CONFIG_KEY_TRUST_PACKED_REFS_STAT = "trustPackedRefsStat";
}
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 92367eb..cf2e69d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -48,6 +48,15 @@ public final class Constants {
*/
public static final int OBJECT_ID_STRING_LENGTH = OBJECT_ID_LENGTH * 2;
+ /**
+ * The historic length of an abbreviated Git object hash string. Git 2.11
+ * changed this static number to a dynamically calculated one that scales
+ * as the repository grows.
+ *
+ * @since 6.1
+ */
+ public static final int OBJECT_ID_ABBREV_STRING_LENGTH = 7;
+
/** Special name for the "HEAD" symbolic-ref. */
public static final String HEAD = "HEAD";
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
index f23c6e0..fc82a5f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -116,6 +116,27 @@ public enum LogRefUpdates {
ALWAYS
}
+ /**
+ * Permissible values for {@code core.trustPackedRefsStat}.
+ *
+ * @since 6.1.1
+ */
+ public enum TrustPackedRefsStat {
+ /** Do not trust file attributes of the packed-refs file. */
+ NEVER,
+
+ /** Trust file attributes of the packed-refs file. */
+ ALWAYS,
+
+ /** Open and close the packed-refs file to refresh its file attributes
+ * and then trust it. */
+ AFTER_OPEN,
+
+ /** {@code core.trustPackedRefsStat} defaults to this when it is
+ * not set */
+ UNSET
+ }
+
private final int compression;
private final int packIndexVersion;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
index 9f96bce..8640940 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
@@ -120,6 +120,26 @@ public int getInt(Config config, String section, String subsection,
/** {@inheritDoc} */
@Override
+ public int getIntInRange(Config config, String section, String subsection,
+ String name, int minValue, int maxValue, int defaultValue) {
+ int val = getInt(config, section, subsection, name, defaultValue);
+ if ((val >= minValue && val <= maxValue) || val == UNSET_INT) {
+ return val;
+ }
+ if (subsection == null) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().integerValueNotInRange, section, name,
+ Integer.valueOf(val), Integer.valueOf(minValue),
+ Integer.valueOf(maxValue)));
+ }
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().integerValueNotInRangeSubSection, section,
+ subsection, name, Integer.valueOf(val),
+ Integer.valueOf(minValue), Integer.valueOf(maxValue)));
+ }
+
+ /** {@inheritDoc} */
+ @Override
public long getLong(Config config, String section, String subsection,
String name, long defaultValue) {
final String str = config.getString(section, subsection, name);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 28ea927..df9fd47 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -568,6 +568,9 @@ public boolean diff(ProgressMonitor monitor, int estWorkTreeSize,
if (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL) {
try (SubmoduleWalk smw = new SubmoduleWalk(repository)) {
smw.setTree(new DirCacheIterator(dirCache));
+ if (filter != null) {
+ smw.setFilter(filter);
+ }
smw.setBuilderFactory(factory);
while (smw.next()) {
IgnoreSubmoduleMode localIgnoreSubmoduleMode = ignoreSubmoduleMode;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
index 04262c0..70009cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java
@@ -155,4 +155,14 @@ public ObjectLoader open(AnyObjectId objectId, int typeHint)
public ObjectDatabase newCachedDatabase() {
return this;
}
+
+ /**
+ * Get a quick, rough count of objects in this repository. Ignores loose
+ * objects. Returns {@code -1} if an exception occurs.
+ *
+ * @return quick, rough count of objects in this repository, {@code -1} if
+ * an exception occurs
+ * @since 6.1
+ */
+ public abstract long getApproximateObjectCount();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
index a2c7381..26c3ff6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
@@ -10,6 +10,8 @@
package org.eclipse.jgit.lib;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -76,7 +78,7 @@ public abstract class ObjectReader implements AutoCloseable {
*/
public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
throws IOException {
- return abbreviate(objectId, 7);
+ return abbreviate(objectId, OBJECT_ID_ABBREV_STRING_LENGTH);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
index 428a6b9..9371029 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -14,6 +14,8 @@
import java.io.Serializable;
import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@@ -206,6 +208,20 @@ public PersonIdent(PersonIdent pi, Date aWhen) {
}
/**
+ * Copy a {@link org.eclipse.jgit.lib.PersonIdent}, but alter the clone's
+ * time stamp
+ *
+ * @param pi
+ * original {@link org.eclipse.jgit.lib.PersonIdent}
+ * @param aWhen
+ * local time as Instant
+ * @since 6.1
+ */
+ public PersonIdent(PersonIdent pi, Instant aWhen) {
+ this(pi.getName(), pi.getEmailAddress(), aWhen.toEpochMilli(), pi.tzOffset);
+ }
+
+ /**
* Construct a PersonIdent from simple data
*
* @param aName a {@link java.lang.String} object.
@@ -222,6 +238,27 @@ public PersonIdent(final String aName, final String aEmailAddress,
}
/**
+ * Construct a PersonIdent from simple data
+ *
+ * @param aName
+ * a {@link java.lang.String} object.
+ * @param aEmailAddress
+ * a {@link java.lang.String} object.
+ * @param aWhen
+ * local time stamp
+ * @param zoneId
+ * time zone id
+ * @since 6.1
+ */
+ public PersonIdent(final String aName, String aEmailAddress, Instant aWhen,
+ ZoneId zoneId) {
+ this(aName, aEmailAddress, aWhen.toEpochMilli(),
+ TimeZone.getTimeZone(zoneId)
+ .getOffset(aWhen
+ .toEpochMilli()) / (60 * 1000));
+ }
+
+ /**
* Copy a PersonIdent, but alter the clone's time stamp
*
* @param pi
@@ -304,6 +341,16 @@ public Date getWhen() {
}
/**
+ * Get when attribute as instant
+ *
+ * @return timestamp
+ * @since 6.1
+ */
+ public Instant getWhenAsInstant() {
+ return Instant.ofEpochMilli(when);
+ }
+
+ /**
* Get this person's declared time zone
*
* @return this person's declared time zone; null if time zone is unknown.
@@ -313,6 +360,16 @@ public TimeZone getTimeZone() {
}
/**
+ * Get the time zone id
+ *
+ * @return the time zone id
+ * @since 6.1
+ */
+ public ZoneId getZoneId() {
+ return getTimeZone().toZoneId();
+ }
+
+ /**
* Get this person's declared time zone as minutes east of UTC.
*
* @return this person's declared time zone as minutes east of UTC. If the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
index 0f2f6cf..c4eb8f1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
@@ -29,6 +29,13 @@
public interface TypedConfigGetter {
/**
+ * Use {@code Integer#MIN_VALUE} as unset int value
+ *
+ * @since 6.1
+ */
+ public static final int UNSET_INT = Integer.MIN_VALUE;
+
+ /**
* Get a boolean value from a git {@link Config}.
*
* @param config
@@ -87,6 +94,32 @@ int getInt(Config config, String section, String subsection, String name,
int defaultValue);
/**
+ * Obtain an integer value from a git {@link Config} which must be in given
+ * range.
+ *
+ * @param config
+ * to get the value from
+ * @param section
+ * section the key is grouped within.
+ * @param subsection
+ * subsection name, such a remote or branch name.
+ * @param name
+ * name of the key to get.
+ * @param minValue
+ * minimal value
+ * @param maxValue
+ * maximum value
+ * @param defaultValue
+ * default value to return if no value was present. Use
+ * {@code #UNSET_INT} to set the default to unset.
+ * @return an integer value from the configuration, or defaultValue.
+ * {@code #UNSET_INT} if unset.
+ * @since 6.1
+ */
+ int getIntInRange(Config config, String section, String subsection,
+ String name, int minValue, int maxValue, int defaultValue);
+
+ /**
* Obtain a long value from a git {@link Config}.
*
* @param config
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BooleanTriState.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BooleanTriState.java
new file mode 100644
index 0000000..44d3bb3
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BooleanTriState.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 Simeon Andreev <simeon.danailov.andreev@gmail.com> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib.internal;
+
+/**
+ * A boolean value that can also have an unset state.
+ */
+public enum BooleanTriState {
+ /**
+ * Value equivalent to {@code true}.
+ */
+ TRUE,
+ /**
+ * Value equivalent to {@code false}.
+ */
+ FALSE,
+ /**
+ * Value is not set.
+ */
+ UNSET;
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
index f7966a2..e0c083f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
@@ -92,36 +92,62 @@ public String format(List<Ref> refsToMerge, Ref target) {
}
/**
- * Add section with conflicting paths to merge message.
+ * Add section with conflicting paths to merge message. Lines are prefixed
+ * with a hash.
*
* @param message
* the original merge message
* @param conflictingPaths
* the paths with conflicts
* @return merge message with conflicting paths added
+ * @deprecated since 6.1; use
+ * {@link #formatWithConflicts(String, Iterable, char)} instead
*/
+ @Deprecated
public String formatWithConflicts(String message,
List<String> conflictingPaths) {
+ return formatWithConflicts(message, conflictingPaths, '#');
+ }
+
+ /**
+ * Add section with conflicting paths to merge message.
+ *
+ * @param message
+ * the original merge message
+ * @param conflictingPaths
+ * the paths with conflicts
+ * @param commentChar
+ * comment character to use for prefixing the conflict lines
+ * @return merge message with conflicting paths added
+ * @since 6.1
+ */
+ public String formatWithConflicts(String message,
+ Iterable<String> conflictingPaths, char commentChar) {
StringBuilder sb = new StringBuilder();
String[] lines = message.split("\n"); //$NON-NLS-1$
int firstFooterLine = ChangeIdUtil.indexOfFirstFooterLine(lines);
- for (int i = 0; i < firstFooterLine; i++)
+ for (int i = 0; i < firstFooterLine; i++) {
sb.append(lines[i]).append('\n');
- if (firstFooterLine == lines.length && message.length() != 0)
+ }
+ if (firstFooterLine == lines.length && message.length() != 0) {
sb.append('\n');
- addConflictsMessage(conflictingPaths, sb);
- if (firstFooterLine < lines.length)
+ }
+ addConflictsMessage(conflictingPaths, sb, commentChar);
+ if (firstFooterLine < lines.length) {
sb.append('\n');
- for (int i = firstFooterLine; i < lines.length; i++)
+ }
+ for (int i = firstFooterLine; i < lines.length; i++) {
sb.append(lines[i]).append('\n');
+ }
return sb.toString();
}
- private static void addConflictsMessage(List<String> conflictingPaths,
- StringBuilder sb) {
- sb.append("Conflicts:\n"); //$NON-NLS-1$
+ private static void addConflictsMessage(Iterable<String> conflictingPaths,
+ StringBuilder sb, char commentChar) {
+ sb.append(commentChar).append(" Conflicts:\n"); //$NON-NLS-1$
for (String conflictingPath : conflictingPaths) {
- sb.append('\t').append(conflictingPath).append('\n');
+ sb.append(commentChar).append('\t').append(conflictingPath)
+ .append('\n');
}
}
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 7767662..b9ab1d1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -3,7 +3,7 @@
* 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)
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -276,11 +276,15 @@ public enum MergeFailureReason {
private ContentMergeStrategy contentStrategy = ContentMergeStrategy.CONFLICT;
/**
- * Keeps {@link CheckoutMetadata} for {@link #checkout()} and
- * {@link #cleanUp()}.
+ * Keeps {@link CheckoutMetadata} for {@link #checkout()}.
*/
private Map<String, CheckoutMetadata> checkoutMetadata;
+ /**
+ * Keeps {@link CheckoutMetadata} for {@link #cleanUp()}.
+ */
+ private Map<String, CheckoutMetadata> cleanupMetadata;
+
private static MergeAlgorithm getMergeAlgorithm(Config config) {
SupportedAlgorithm diffAlg = config.getEnum(
CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM,
@@ -383,12 +387,14 @@ protected boolean mergeImpl() throws IOException {
}
if (!inCore) {
checkoutMetadata = new HashMap<>();
+ cleanupMetadata = new HashMap<>();
}
try {
return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
false);
} finally {
checkoutMetadata = null;
+ cleanupMetadata = null;
if (implicitDirCache) {
dircache.unlock();
}
@@ -447,7 +453,7 @@ protected void cleanUp() throws NoWorkTreeException,
DirCacheEntry entry = dc.getEntry(mpath);
if (entry != null) {
DirCacheCheckout.checkoutEntry(db, entry, reader, false,
- checkoutMetadata.get(mpath));
+ cleanupMetadata.get(mpath));
}
mpathsIt.remove();
}
@@ -501,22 +507,26 @@ private DirCacheEntry keep(DirCacheEntry e) {
* Remembers the {@link CheckoutMetadata} for the given path; it may be
* needed in {@link #checkout()} or in {@link #cleanUp()}.
*
+ * @param map
+ * to add the metadata to
* @param path
* of the current node
* @param attributes
- * for the current node
+ * to use for determining the metadata
* @throws IOException
* if the smudge filter cannot be determined
- * @since 5.1
+ * @since 6.1
*/
- protected void addCheckoutMetadata(String path, Attributes attributes)
+ protected void addCheckoutMetadata(Map<String, CheckoutMetadata> map,
+ String path, Attributes attributes)
throws IOException {
- if (checkoutMetadata != null) {
+ if (map != null) {
EolStreamType eol = EolStreamTypeUtil.detectStreamType(
- OperationType.CHECKOUT_OP, workingTreeOptions, attributes);
+ OperationType.CHECKOUT_OP, workingTreeOptions,
+ attributes);
CheckoutMetadata data = new CheckoutMetadata(eol,
- tw.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE));
- checkoutMetadata.put(path, data);
+ tw.getSmudgeCommand(attributes));
+ map.put(path, data);
}
}
@@ -529,15 +539,17 @@ protected void addCheckoutMetadata(String path, Attributes attributes)
* @param entry
* to add
* @param attributes
- * for the current entry
+ * the {@link Attributes} of the trees
* @throws IOException
* if the {@link CheckoutMetadata} cannot be determined
- * @since 5.1
+ * @since 6.1
*/
protected void addToCheckout(String path, DirCacheEntry entry,
- Attributes attributes) throws IOException {
+ Attributes[] attributes)
+ throws IOException {
toBeCheckedOut.put(path, entry);
- addCheckoutMetadata(path, attributes);
+ addCheckoutMetadata(cleanupMetadata, path, attributes[T_OURS]);
+ addCheckoutMetadata(checkoutMetadata, path, attributes[T_THEIRS]);
}
/**
@@ -549,7 +561,7 @@ protected void addToCheckout(String path, DirCacheEntry entry,
* @param isFile
* whether it is a file
* @param attributes
- * for the entry
+ * to use for determining the {@link CheckoutMetadata}
* @throws IOException
* if the {@link CheckoutMetadata} cannot be determined
* @since 5.1
@@ -558,7 +570,7 @@ protected void addDeletion(String path, boolean isFile,
Attributes attributes) throws IOException {
toBeDeleted.add(path);
if (isFile) {
- addCheckoutMetadata(path, attributes);
+ addCheckoutMetadata(cleanupMetadata, path, attributes);
}
}
@@ -599,7 +611,7 @@ protected void addDeletion(String path, boolean isFile,
* see
* {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
* @param attributes
- * the attributes defined for this entry
+ * the {@link Attributes} for the three trees
* @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
@@ -607,12 +619,12 @@ protected void addDeletion(String path, boolean isFile,
* @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
* @throws org.eclipse.jgit.errors.CorruptObjectException
* @throws java.io.IOException
- * @since 4.9
+ * @since 6.1
*/
protected boolean processEntry(CanonicalTreeParser base,
CanonicalTreeParser ours, CanonicalTreeParser theirs,
DirCacheBuildIterator index, WorkingTreeIterator work,
- boolean ignoreConflicts, Attributes attributes)
+ boolean ignoreConflicts, Attributes[] attributes)
throws MissingObjectException, IncorrectObjectTypeException,
CorruptObjectException, IOException {
enterSubtree = true;
@@ -729,7 +741,7 @@ protected boolean processEntry(CanonicalTreeParser base,
// Base, ours, and theirs all contain a folder: don't delete
return true;
}
- addDeletion(tw.getPathString(), nonTree(modeO), attributes);
+ addDeletion(tw.getPathString(), nonTree(modeO), attributes[T_OURS]);
return true;
}
@@ -772,7 +784,7 @@ protected boolean processEntry(CanonicalTreeParser base,
if (nonTree(modeO) && nonTree(modeT)) {
// Check worktree before modifying files
boolean worktreeDirty = isWorktreeDirty(work, ourDce);
- if (!attributes.canBeContentMerged() && worktreeDirty) {
+ if (!attributes[T_OURS].canBeContentMerged() && worktreeDirty) {
return false;
}
@@ -791,7 +803,7 @@ protected boolean processEntry(CanonicalTreeParser base,
mergeResults.put(tw.getPathString(), result);
unmergedPaths.add(tw.getPathString());
return true;
- } else if (!attributes.canBeContentMerged()) {
+ } else if (!attributes[T_OURS].canBeContentMerged()) {
// File marked as binary
switch (getContentMergeStrategy()) {
case OURS:
@@ -842,13 +854,16 @@ protected boolean processEntry(CanonicalTreeParser base,
if (ignoreConflicts) {
result.setContainsConflicts(false);
}
- updateIndex(base, ours, theirs, result, attributes);
+ updateIndex(base, ours, theirs, result, attributes[T_OURS]);
String currentPath = tw.getPathString();
if (result.containsConflicts() && !ignoreConflicts) {
unmergedPaths.add(currentPath);
}
modifiedFiles.add(currentPath);
- addCheckoutMetadata(currentPath, attributes);
+ addCheckoutMetadata(cleanupMetadata, currentPath,
+ attributes[T_OURS]);
+ addCheckoutMetadata(checkoutMetadata, currentPath,
+ attributes[T_THEIRS]);
} else if (modeO != modeT) {
// OURS or THEIRS has been deleted
if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
@@ -881,7 +896,8 @@ protected boolean processEntry(CanonicalTreeParser base,
// markers). But also stage 0 of the index is filled
// with that content.
result.setContainsConflicts(false);
- updateIndex(base, ours, theirs, result, attributes);
+ updateIndex(base, ours, theirs, result,
+ attributes[T_OURS]);
} else {
add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH,
0);
@@ -896,11 +912,9 @@ protected boolean processEntry(CanonicalTreeParser base,
if (isWorktreeDirty(work, ourDce)) {
return false;
}
- if (nonTree(modeT)) {
- if (e != null) {
- addToCheckout(tw.getPathString(), e,
- attributes);
- }
+ if (nonTree(modeT) && e != null) {
+ addToCheckout(tw.getPathString(), e,
+ attributes);
}
}
@@ -945,14 +959,16 @@ private static MergeResult<SubmoduleConflict> createGitLinksMergeResult(
*/
private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
CanonicalTreeParser ours, CanonicalTreeParser theirs,
- Attributes attributes, ContentMergeStrategy strategy)
+ Attributes[] attributes, ContentMergeStrategy strategy)
throws BinaryBlobException, IOException {
+ // TW: The attributes here are used to determine the LFS smudge filter.
+ // Is doing a content merge on LFS items really a good idea??
RawText baseText = base == null ? RawText.EMPTY_TEXT
- : getRawText(base.getEntryObjectId(), attributes);
+ : getRawText(base.getEntryObjectId(), attributes[T_BASE]);
RawText ourText = ours == null ? RawText.EMPTY_TEXT
- : getRawText(ours.getEntryObjectId(), attributes);
+ : getRawText(ours.getEntryObjectId(), attributes[T_OURS]);
RawText theirsText = theirs == null ? RawText.EMPTY_TEXT
- : getRawText(theirs.getEntryObjectId(), attributes);
+ : getRawText(theirs.getEntryObjectId(), attributes[T_THEIRS]);
mergeAlgorithm.setContentMergeStrategy(strategy);
return mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
ourText, theirsText);
@@ -1342,7 +1358,7 @@ protected boolean mergeTrees(AbstractTreeIterator baseTree,
tw = new NameConflictTreeWalk(db, reader);
tw.addTree(baseTree);
- tw.addTree(headTree);
+ tw.setHead(tw.addTree(headTree));
tw.addTree(mergeTree);
int dciPos = tw.addTree(buildIt);
if (workingTreeIterator != null) {
@@ -1403,6 +1419,13 @@ protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
boolean hasAttributeNodeProvider = treeWalk
.getAttributesNodeProvider() != null;
while (treeWalk.next()) {
+ Attributes[] attributes = { NO_ATTRIBUTES, NO_ATTRIBUTES,
+ NO_ATTRIBUTES };
+ if (hasAttributeNodeProvider) {
+ attributes[T_BASE] = treeWalk.getAttributes(T_BASE);
+ attributes[T_OURS] = treeWalk.getAttributes(T_OURS);
+ attributes[T_THEIRS] = treeWalk.getAttributes(T_THEIRS);
+ }
if (!processEntry(
treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
treeWalk.getTree(T_OURS, CanonicalTreeParser.class),
@@ -1410,9 +1433,7 @@ protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
WorkingTreeIterator.class) : null,
- ignoreConflicts, hasAttributeNodeProvider
- ? treeWalk.getAttributes()
- : NO_ATTRIBUTES)) {
+ ignoreConflicts, attributes)) {
cleanUp();
return false;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
index e6f9580..4e48a5c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -139,7 +139,7 @@ public void visited(RevObject o) {
* the repository the walker will obtain data from.
*/
public ObjectWalk(Repository repo) {
- this(repo.newObjectReader());
+ this(repo.newObjectReader(), true);
}
/**
@@ -151,7 +151,11 @@ public ObjectWalk(Repository repo) {
* required.
*/
public ObjectWalk(ObjectReader or) {
- super(or);
+ this(or, false);
+ }
+
+ private ObjectWalk(ObjectReader or, boolean closeReader) {
+ super(or, closeReader);
setRetainBody(false);
rootObjects = new ArrayList<>();
pendingObjects = new BlockObjQueue();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 8d571f5..a50eaf1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -215,7 +215,7 @@ public RevWalk(ObjectReader or) {
this(or, false);
}
- private RevWalk(ObjectReader or, boolean closeReader) {
+ RevWalk(ObjectReader or, boolean closeReader) {
reader = or;
idBuffer = new MutableObjectId();
objects = new ObjectIdOwnerMap<>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java
index fda7a81..c8774d5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017, David Pursehouse <david.pursehouse@gmail.com> and others
+ * Copyright (C) 2017, 2022 David Pursehouse <david.pursehouse@gmail.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -10,7 +10,10 @@
package org.eclipse.jgit.transport;
+import java.util.Locale;
+
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.util.StringUtils;
/**
@@ -19,8 +22,9 @@
* @since 4.9
*/
public class PushConfig {
+
/**
- * Config values for push.recurseSubmodules.
+ * Git config values for {@code push.recurseSubmodules}.
*/
public enum PushRecurseSubmodulesMode implements Config.ConfigEnum {
/**
@@ -59,4 +63,100 @@ public boolean matchConfigValue(String s) {
|| configValue.equalsIgnoreCase(s);
}
}
+
+ /**
+ * Git config values for {@code push.default}.
+ *
+ * @since 6.1
+ */
+ public enum PushDefault implements Config.ConfigEnum {
+
+ /**
+ * Do not push if there are no explicit refspecs.
+ */
+ NOTHING,
+
+ /**
+ * Push the current branch to an upstream branch of the same name.
+ */
+ CURRENT,
+
+ /**
+ * Push the current branch to an upstream branch determined by git
+ * config {@code branch.<currentBranch>.merge}.
+ */
+ UPSTREAM("tracking"), //$NON-NLS-1$
+
+ /**
+ * Like {@link #UPSTREAM}, but only if the upstream name is the same as
+ * the name of the current local branch.
+ */
+ SIMPLE,
+
+ /**
+ * Push all current local branches that match a configured push refspec
+ * of the remote configuration.
+ */
+ MATCHING;
+
+ private final String alias;
+
+ private PushDefault() {
+ alias = null;
+ }
+
+ private PushDefault(String alias) {
+ this.alias = alias;
+ }
+
+ @Override
+ public String toConfigValue() {
+ return name().toLowerCase(Locale.ROOT);
+ }
+
+ @Override
+ public boolean matchConfigValue(String in) {
+ return toConfigValue().equalsIgnoreCase(in)
+ || (alias != null && alias.equalsIgnoreCase(in));
+ }
+ }
+
+ private final PushRecurseSubmodulesMode recurseSubmodules;
+
+ private final PushDefault pushDefault;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param config
+ * {@link Config} to fill the {@link PushConfig} from
+ * @since 6.1
+ */
+ public PushConfig(Config config) {
+ recurseSubmodules = config.getEnum(ConfigConstants.CONFIG_PUSH_SECTION,
+ null, ConfigConstants.CONFIG_KEY_RECURSE_SUBMODULES,
+ PushRecurseSubmodulesMode.NO);
+ pushDefault = config.getEnum(ConfigConstants.CONFIG_PUSH_SECTION, null,
+ ConfigConstants.CONFIG_KEY_DEFAULT, PushDefault.SIMPLE);
+ }
+
+ /**
+ * Retrieves the value of git config {@code push.recurseSubmodules}.
+ *
+ * @return the value
+ * @since 6.1
+ */
+ public PushRecurseSubmodulesMode getRecurseSubmodules() {
+ return recurseSubmodules;
+ }
+
+ /**
+ * Retrieves the value of git config {@code push.default}.
+ *
+ * @return the value
+ * @since 6.1
+ */
+ public PushDefault getPushDefault() {
+ return pushDefault;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
index a244c55..942dad4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -18,11 +18,15 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.hooks.PrePushHook;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
@@ -58,6 +62,8 @@ class PushProcess {
/** A list of option strings associated with this push */
private List<String> pushOptions;
+ private final PrePushHook prePush;
+
/**
* Create process for specified transport and refs updates specification.
*
@@ -66,12 +72,14 @@ class PushProcess {
* connection.
* @param toPush
* specification of refs updates (and local tracking branches).
- *
+ * @param prePush
+ * {@link PrePushHook} to run after the remote advertisement has
+ * been gotten
* @throws TransportException
*/
- PushProcess(final Transport transport,
- final Collection<RemoteRefUpdate> toPush) throws TransportException {
- this(transport, toPush, null);
+ PushProcess(Transport transport, Collection<RemoteRefUpdate> toPush,
+ PrePushHook prePush) throws TransportException {
+ this(transport, toPush, prePush, null);
}
/**
@@ -82,16 +90,19 @@ class PushProcess {
* connection.
* @param toPush
* specification of refs updates (and local tracking branches).
+ * @param prePush
+ * {@link PrePushHook} to run after the remote advertisement has
+ * been gotten
* @param out
* OutputStream to write messages to
* @throws TransportException
*/
- PushProcess(final Transport transport,
- final Collection<RemoteRefUpdate> toPush, OutputStream out)
- throws TransportException {
+ PushProcess(Transport transport, Collection<RemoteRefUpdate> toPush,
+ PrePushHook prePush, OutputStream out) throws TransportException {
this.walker = new RevWalk(transport.local);
this.transport = transport;
this.toPush = new LinkedHashMap<>();
+ this.prePush = prePush;
this.out = out;
this.pushOptions = transport.getPushOptions();
for (RemoteRefUpdate rru : toPush) {
@@ -129,10 +140,38 @@ PushResult execute(ProgressMonitor monitor)
res.setAdvertisedRefs(transport.getURI(), connection
.getRefsMap());
res.peerUserAgent = connection.getPeerUserAgent();
- res.setRemoteUpdates(toPush);
monitor.endTask();
+ Map<String, RemoteRefUpdate> expanded = expandMatching();
+ toPush.clear();
+ toPush.putAll(expanded);
+
+ res.setRemoteUpdates(toPush);
final Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates();
+ List<RemoteRefUpdate> willBeAttempted = preprocessed.values()
+ .stream().filter(u -> {
+ switch (u.getStatus()) {
+ case NON_EXISTING:
+ case REJECTED_NODELETE:
+ case REJECTED_NONFASTFORWARD:
+ case REJECTED_OTHER_REASON:
+ case REJECTED_REMOTE_CHANGED:
+ case UP_TO_DATE:
+ return false;
+ default:
+ return true;
+ }
+ }).collect(Collectors.toList());
+ if (!willBeAttempted.isEmpty()) {
+ if (prePush != null) {
+ try {
+ prePush.setRefs(willBeAttempted);
+ prePush.call();
+ } catch (AbortedByHookException | IOException e) {
+ throw new TransportException(e.getMessage(), e);
+ }
+ }
+ }
if (transport.isDryRun())
modifyUpdatesForDryRun();
else if (!preprocessed.isEmpty())
@@ -201,25 +240,8 @@ private Map<String, RemoteRefUpdate> prepareRemoteUpdates()
continue;
}
- // check for fast-forward:
- // - both old and new ref must point to commits, AND
- // - both of them must be known for us, exist in repository, AND
- // - old commit must be ancestor of new commit
- boolean fastForward = true;
- try {
- RevObject oldRev = walker.parseAny(advertisedOld);
- final RevObject newRev = walker.parseAny(rru.getNewObjectId());
- if (!(oldRev instanceof RevCommit)
- || !(newRev instanceof RevCommit)
- || !walker.isMergedInto((RevCommit) oldRev,
- (RevCommit) newRev))
- fastForward = false;
- } catch (MissingObjectException x) {
- fastForward = false;
- } catch (Exception x) {
- throw new TransportException(transport.getURI(), MessageFormat.format(
- JGitText.get().readingObjectsFromLocalRepositoryFailed, x.getMessage()), x);
- }
+ boolean fastForward = isFastForward(advertisedOld,
+ rru.getNewObjectId());
rru.setFastForward(fastForward);
if (!fastForward && !rru.isForceUpdate()) {
rru.setStatus(Status.REJECTED_NONFASTFORWARD);
@@ -233,6 +255,134 @@ private Map<String, RemoteRefUpdate> prepareRemoteUpdates()
return result;
}
+ /**
+ * Determines whether an update from {@code oldOid} to {@code newOid} is a
+ * fast-forward update:
+ * <ul>
+ * <li>both old and new must be commits, AND</li>
+ * <li>both of them must be known to us and exist in the repository,
+ * AND</li>
+ * <li>the old commit must be an ancestor of the new commit.</li>
+ * </ul>
+ *
+ * @param oldOid
+ * {@link ObjectId} of the old commit
+ * @param newOid
+ * {@link ObjectId} of the new commit
+ * @return {@code true} if the update fast-forwards, {@code false} otherwise
+ * @throws TransportException
+ */
+ private boolean isFastForward(ObjectId oldOid, ObjectId newOid)
+ throws TransportException {
+ try {
+ RevObject oldRev = walker.parseAny(oldOid);
+ RevObject newRev = walker.parseAny(newOid);
+ if (!(oldRev instanceof RevCommit) || !(newRev instanceof RevCommit)
+ || !walker.isMergedInto((RevCommit) oldRev,
+ (RevCommit) newRev)) {
+ return false;
+ }
+ } catch (MissingObjectException x) {
+ return false;
+ } catch (Exception x) {
+ throw new TransportException(transport.getURI(),
+ MessageFormat.format(JGitText
+ .get().readingObjectsFromLocalRepositoryFailed,
+ x.getMessage()),
+ x);
+ }
+ return true;
+ }
+
+ /**
+ * Expands all placeholder {@link RemoteRefUpdate}s for "matching"
+ * {@link RefSpec}s ":" in {@link #toPush} and returns the resulting map in
+ * which the placeholders have been replaced by their expansion.
+ *
+ * @return a new map of {@link RemoteRefUpdate}s keyed by remote name
+ * @throws TransportException
+ * if the expansion results in duplicate updates
+ */
+ private Map<String, RemoteRefUpdate> expandMatching()
+ throws TransportException {
+ Map<String, RemoteRefUpdate> result = new LinkedHashMap<>();
+ boolean hadMatch = false;
+ for (RemoteRefUpdate update : toPush.values()) {
+ if (update.isMatching()) {
+ if (hadMatch) {
+ throw new TransportException(MessageFormat.format(
+ JGitText.get().duplicateRemoteRefUpdateIsIllegal,
+ ":")); //$NON-NLS-1$
+ }
+ expandMatching(result, update);
+ hadMatch = true;
+ } else if (result.put(update.getRemoteName(), update) != null) {
+ throw new TransportException(MessageFormat.format(
+ JGitText.get().duplicateRemoteRefUpdateIsIllegal,
+ update.getRemoteName()));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Expands the placeholder {@link RemoteRefUpdate} {@code match} for a
+ * "matching" {@link RefSpec} ":" or "+:" and puts the expansion into the
+ * given map {@code updates}.
+ *
+ * @param updates
+ * map to put the expansion in
+ * @param match
+ * the placeholder {@link RemoteRefUpdate} to expand
+ *
+ * @throws TransportException
+ * if the expansion results in duplicate updates, or the local
+ * branches cannot be determined
+ */
+ private void expandMatching(Map<String, RemoteRefUpdate> updates,
+ RemoteRefUpdate match) throws TransportException {
+ try {
+ Map<String, Ref> advertisement = connection.getRefsMap();
+ Collection<RefSpec> fetchSpecs = match.getFetchSpecs();
+ boolean forceUpdate = match.isForceUpdate();
+ for (Ref local : transport.local.getRefDatabase()
+ .getRefsByPrefix(Constants.R_HEADS)) {
+ if (local.isSymbolic()) {
+ continue;
+ }
+ String name = local.getName();
+ Ref advertised = advertisement.get(name);
+ if (advertised == null || advertised.isSymbolic()) {
+ continue;
+ }
+ ObjectId oldOid = advertised.getObjectId();
+ if (oldOid == null || ObjectId.zeroId().equals(oldOid)) {
+ continue;
+ }
+ ObjectId newOid = local.getObjectId();
+ if (newOid == null || ObjectId.zeroId().equals(newOid)) {
+ continue;
+ }
+
+ RemoteRefUpdate rru = new RemoteRefUpdate(transport.local, name,
+ newOid, name, forceUpdate,
+ Transport.findTrackingRefName(name, fetchSpecs),
+ oldOid);
+ if (updates.put(rru.getRemoteName(), rru) != null) {
+ throw new TransportException(MessageFormat.format(
+ JGitText.get().duplicateRemoteRefUpdateIsIllegal,
+ rru.getRemoteName()));
+ }
+ }
+ } catch (IOException x) {
+ throw new TransportException(transport.getURI(),
+ MessageFormat.format(JGitText
+ .get().readingObjectsFromLocalRepositoryFailed,
+ x.getMessage()),
+ x);
+ }
+ }
+
private Map<String, RemoteRefUpdate> rejectAll() {
for (RemoteRefUpdate rru : toPush.values()) {
if (rru.getStatus() == Status.NOT_ATTEMPTED) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
index ac357af..56d0036 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
@@ -12,11 +12,11 @@
import java.io.Serializable;
import java.text.MessageFormat;
+import java.util.Objects;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.util.References;
/**
* Describes how refs in one repository copy into another repository.
@@ -50,6 +50,9 @@ public static boolean isWildcard(String s) {
/** Is this specification actually a wildcard match? */
private boolean wildcard;
+ /** Is this the special ":" RefSpec? */
+ private boolean matching;
+
/**
* How strict to be about wildcards.
*
@@ -71,6 +74,7 @@ public enum WildcardMode {
*/
ALLOW_MISMATCH
}
+
/** Whether a wildcard is allowed on one side but not the other. */
private WildcardMode allowMismatchedWildcards;
@@ -87,6 +91,7 @@ public enum WildcardMode {
* applications, as at least one field must be set to match a source name.
*/
public RefSpec() {
+ matching = false;
force = false;
wildcard = false;
srcName = Constants.HEAD;
@@ -133,17 +138,25 @@ public RefSpec(String spec, WildcardMode mode) {
s = s.substring(1);
}
+ boolean matchPushSpec = false;
final int c = s.lastIndexOf(':');
if (c == 0) {
s = s.substring(1);
- if (isWildcard(s)) {
+ if (s.isEmpty()) {
+ matchPushSpec = true;
wildcard = true;
- if (mode == WildcardMode.REQUIRE_MATCH) {
- throw new IllegalArgumentException(MessageFormat
- .format(JGitText.get().invalidWildcards, spec));
+ srcName = Constants.R_HEADS + '*';
+ dstName = srcName;
+ } else {
+ if (isWildcard(s)) {
+ wildcard = true;
+ if (mode == WildcardMode.REQUIRE_MATCH) {
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidWildcards, spec));
+ }
}
+ dstName = checkValid(s);
}
- dstName = checkValid(s);
} else if (c > 0) {
String src = s.substring(0, c);
String dst = s.substring(c + 1);
@@ -168,6 +181,7 @@ public RefSpec(String spec, WildcardMode mode) {
}
srcName = checkValid(s);
}
+ matching = matchPushSpec;
}
/**
@@ -195,6 +209,7 @@ public RefSpec(String spec) {
}
private RefSpec(RefSpec p) {
+ matching = false;
force = p.isForceUpdate();
wildcard = p.isWildcard();
srcName = p.getSource();
@@ -203,6 +218,17 @@ private RefSpec(RefSpec p) {
}
/**
+ * Tells whether this {@link RefSpec} is the special "matching" RefSpec ":"
+ * for pushing.
+ *
+ * @return whether this is a "matching" RefSpec
+ * @since 6.1
+ */
+ public boolean isMatching() {
+ return matching;
+ }
+
+ /**
* Check if this specification wants to forcefully update the destination.
*
* @return true if this specification asks for updates without merge tests.
@@ -220,6 +246,7 @@ public boolean isForceUpdate() {
*/
public RefSpec setForceUpdate(boolean forceUpdate) {
final RefSpec r = new RefSpec(this);
+ r.matching = matching;
r.force = forceUpdate;
return r;
}
@@ -322,8 +349,7 @@ public RefSpec setDestination(String destination) {
* The wildcard status of the new source disagrees with the
* wildcard status of the new destination.
*/
- public RefSpec setSourceDestination(final String source,
- final String destination) {
+ public RefSpec setSourceDestination(String source, String destination) {
if (isWildcard(source) != isWildcard(destination))
throw new IllegalStateException(JGitText.get().sourceDestinationMustMatch);
final RefSpec r = new RefSpec(this);
@@ -541,37 +567,36 @@ public boolean equals(Object obj) {
if (!(obj instanceof RefSpec))
return false;
final RefSpec b = (RefSpec) obj;
- if (isForceUpdate() != b.isForceUpdate())
+ if (isForceUpdate() != b.isForceUpdate()) {
return false;
- if (isWildcard() != b.isWildcard())
- return false;
- if (!eq(getSource(), b.getSource()))
- return false;
- if (!eq(getDestination(), b.getDestination()))
- return false;
- return true;
- }
-
- private static boolean eq(String a, String b) {
- if (References.isSameObject(a, b)) {
- return true;
}
- if (a == null || b == null)
+ if (isMatching()) {
+ return b.isMatching();
+ } else if (b.isMatching()) {
return false;
- return a.equals(b);
+ }
+ return isWildcard() == b.isWildcard()
+ && Objects.equals(getSource(), b.getSource())
+ && Objects.equals(getDestination(), b.getDestination());
}
/** {@inheritDoc} */
@Override
public String toString() {
final StringBuilder r = new StringBuilder();
- if (isForceUpdate())
+ if (isForceUpdate()) {
r.append('+');
- if (getSource() != null)
- r.append(getSource());
- if (getDestination() != null) {
+ }
+ if (isMatching()) {
r.append(':');
- r.append(getDestination());
+ } else {
+ if (getSource() != null) {
+ r.append(getSource());
+ }
+ if (getDestination() != null) {
+ r.append(':');
+ r.append(getDestination());
+ }
}
return r.toString();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
index 43eaac7..218e62c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
@@ -12,7 +12,9 @@
import java.io.IOException;
import java.text.MessageFormat;
+import java.util.Collection;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -116,6 +118,12 @@ public enum Status {
private RefUpdate localUpdate;
/**
+ * If set, the RemoteRefUpdate is a placeholder for the "matching" RefSpec
+ * to be expanded after the advertisements have been received in a push.
+ */
+ private Collection<RefSpec> fetchSpecs;
+
+ /**
* Construct remote ref update request by providing an update specification.
* Object is created with default
* {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
@@ -157,9 +165,8 @@ public enum Status {
* @throws java.lang.IllegalArgumentException
* if some required parameter was null
*/
- public RemoteRefUpdate(final Repository localDb, final String srcRef,
- final String remoteName, final boolean forceUpdate,
- final String localName, final ObjectId expectedOldObjectId)
+ public RemoteRefUpdate(Repository localDb, String srcRef, String remoteName,
+ boolean forceUpdate, String localName, ObjectId expectedOldObjectId)
throws IOException {
this(localDb, srcRef, srcRef != null ? localDb.resolve(srcRef)
: ObjectId.zeroId(), remoteName, forceUpdate, localName,
@@ -203,9 +210,8 @@ public RemoteRefUpdate(final Repository localDb, final String srcRef,
* @throws java.lang.IllegalArgumentException
* if some required parameter was null
*/
- public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
- final String remoteName, final boolean forceUpdate,
- final String localName, final ObjectId expectedOldObjectId)
+ public RemoteRefUpdate(Repository localDb, Ref srcRef, String remoteName,
+ boolean forceUpdate, String localName, ObjectId expectedOldObjectId)
throws IOException {
this(localDb, srcRef != null ? srcRef.getName() : null,
srcRef != null ? srcRef.getObjectId() : null, remoteName,
@@ -255,28 +261,41 @@ public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
* @throws java.lang.IllegalArgumentException
* if some required parameter was null
*/
- public RemoteRefUpdate(final Repository localDb, final String srcRef,
- final ObjectId srcId, final String remoteName,
- final boolean forceUpdate, final String localName,
- final ObjectId expectedOldObjectId) throws IOException {
- if (remoteName == null)
- throw new IllegalArgumentException(JGitText.get().remoteNameCannotBeNull);
- if (srcId == null && srcRef != null)
- throw new IOException(MessageFormat.format(
- JGitText.get().sourceRefDoesntResolveToAnyObject, srcRef));
+ public RemoteRefUpdate(Repository localDb, String srcRef, ObjectId srcId,
+ String remoteName, boolean forceUpdate, String localName,
+ ObjectId expectedOldObjectId) throws IOException {
+ this(localDb, srcRef, srcId, remoteName, forceUpdate, localName, null,
+ expectedOldObjectId);
+ }
- if (srcRef != null)
+ private RemoteRefUpdate(Repository localDb, String srcRef, ObjectId srcId,
+ String remoteName, boolean forceUpdate, String localName,
+ Collection<RefSpec> fetchSpecs, ObjectId expectedOldObjectId)
+ throws IOException {
+ if (fetchSpecs == null) {
+ if (remoteName == null) {
+ throw new IllegalArgumentException(
+ JGitText.get().remoteNameCannotBeNull);
+ }
+ if (srcId == null && srcRef != null) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().sourceRefDoesntResolveToAnyObject,
+ srcRef));
+ }
+ }
+ if (srcRef != null) {
this.srcRef = srcRef;
- else if (srcId != null && !srcId.equals(ObjectId.zeroId()))
+ } else if (srcId != null && !srcId.equals(ObjectId.zeroId())) {
this.srcRef = srcId.name();
- else
+ } else {
this.srcRef = null;
-
- if (srcId != null)
+ }
+ if (srcId != null) {
this.newObjectId = srcId;
- else
+ } else {
this.newObjectId = ObjectId.zeroId();
-
+ }
+ this.fetchSpecs = fetchSpecs;
this.remoteName = remoteName;
this.forceUpdate = forceUpdate;
if (localName != null && localDb != null) {
@@ -292,8 +311,9 @@ else if (srcId != null && !srcId.equals(ObjectId.zeroId()))
? localUpdate.getOldObjectId()
: ObjectId.zeroId(),
newObjectId);
- } else
+ } else {
trackingRefUpdate = null;
+ }
this.localDb = localDb;
this.expectedOldObjectId = expectedOldObjectId;
this.status = Status.NOT_ATTEMPTED;
@@ -316,11 +336,57 @@ else if (srcId != null && !srcId.equals(ObjectId.zeroId()))
* local tracking branch or srcRef of base object no longer can
* be resolved to any object.
*/
- public RemoteRefUpdate(final RemoteRefUpdate base,
- final ObjectId newExpectedOldObjectId) throws IOException {
- this(base.localDb, base.srcRef, base.remoteName, base.forceUpdate,
+ public RemoteRefUpdate(RemoteRefUpdate base,
+ ObjectId newExpectedOldObjectId) throws IOException {
+ this(base.localDb, base.srcRef, base.newObjectId, base.remoteName,
+ base.forceUpdate,
(base.trackingRefUpdate == null ? null : base.trackingRefUpdate
- .getLocalName()), newExpectedOldObjectId);
+ .getLocalName()),
+ base.fetchSpecs, newExpectedOldObjectId);
+ }
+
+ /**
+ * Creates a "placeholder" update for the "matching" RefSpec ":".
+ *
+ * @param localDb
+ * local repository to push from
+ * @param forceUpdate
+ * whether non-fast-forward updates shall be allowed
+ * @param fetchSpecs
+ * The fetch {@link RefSpec}s to use when this placeholder is
+ * expanded to determine remote tracking branch updates
+ */
+ RemoteRefUpdate(Repository localDb, boolean forceUpdate,
+ @NonNull Collection<RefSpec> fetchSpecs) {
+ this.localDb = localDb;
+ this.forceUpdate = forceUpdate;
+ this.fetchSpecs = fetchSpecs;
+ this.trackingRefUpdate = null;
+ this.srcRef = null;
+ this.remoteName = null;
+ this.newObjectId = null;
+ this.status = Status.NOT_ATTEMPTED;
+ }
+
+ /**
+ * Tells whether this {@link RemoteRefUpdate} is a placeholder for a
+ * "matching" {@link RefSpec}.
+ *
+ * @return {@code true} if this is a placeholder, {@code false} otherwise
+ * @since 6.1
+ */
+ public boolean isMatching() {
+ return fetchSpecs != null;
+ }
+
+ /**
+ * Retrieves the fetch {@link RefSpec}s of this {@link RemoteRefUpdate}.
+ *
+ * @return the fetch {@link RefSpec}s, or {@code null} if
+ * {@code this.}{@link #isMatching()} {@code == false}
+ */
+ Collection<RefSpec> getFetchSpecs() {
+ return fetchSpecs;
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java
index 212a4e4..48cacf0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -44,6 +44,14 @@ private SshConstants() {
// Config file keys
+ /**
+ * Property to control whether private keys are added to an SSH agent, if
+ * one is running, after having been loaded.
+ *
+ * @since 6.1
+ */
+ public static final String ADD_KEYS_TO_AGENT = "AddKeysToAgent";
+
/** Key in an ssh config file. */
public static final String BATCH_MODE = "BatchMode";
@@ -62,6 +70,15 @@ private SshConstants() {
/** Key in an ssh config file. */
public static final String CONNECTION_ATTEMPTS = "ConnectionAttempts";
+ /**
+ * An OpenSSH time value for the connection timeout. In OpenSSH, this
+ * includes everything until the end of the initial key exchange; in JGit it
+ * covers only the underlying TCP connect.
+ *
+ * @since 6.1
+ */
+ public static final String CONNECT_TIMEOUT = "ConnectTimeout";
+
/** Key in an ssh config file. */
public static final String CONTROL_PATH = "ControlPath";
@@ -159,6 +176,14 @@ private SshConstants() {
/** Key in an ssh config file. */
public static final String REMOTE_FORWARD = "RemoteForward";
+ /**
+ * (Absolute) path to a middleware library the SSH agent shall use to load
+ * SK (U2F) keys.
+ *
+ * @since 6.1
+ */
+ public static final String SECURITY_KEY_PROVIDER = "SecurityKeyProvider";
+
/** Key in an ssh config file. */
public static final String SEND_ENV = "SendEnv";
@@ -229,4 +254,12 @@ private SshConstants() {
public static final String[] DEFAULT_IDENTITIES = { //
ID_RSA, ID_DSA, ID_ECDSA, ID_ED25519
};
+
+ /**
+ * Name of the environment variable holding the Unix domain socket for
+ * communication with an SSH agent.
+ *
+ * @since 6.1
+ */
+ public static final String ENV_SSH_AUTH_SOCKET = "SSH_AUTH_SOCK";
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
index 696ca7c..51bc07c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
@@ -12,6 +12,8 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;
+
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
@@ -184,9 +186,13 @@ public String toString() {
if (forceUpdate)
sb.append(" (forced)");
sb.append(" ");
- sb.append(oldObjectId == null ? "" : oldObjectId.abbreviate(7).name());
+ sb.append(oldObjectId == null ? ""
+ : oldObjectId.abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH)
+ .name());
sb.append("..");
- sb.append(newObjectId == null ? "" : newObjectId.abbreviate(7).name());
+ sb.append(newObjectId == null ? ""
+ : newObjectId.abbreviate(OBJECT_ID_ABBREV_STRING_LENGTH)
+ .name());
sb.append("]");
return sb.toString();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 5b781ac..0eab443 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -2,7 +2,7 @@
* Copyright (C) 2008, 2009 Google Inc.
* Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -40,7 +40,6 @@
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
-import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.hooks.Hooks;
@@ -590,6 +589,11 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
final Collection<RefSpec> procRefs = expandPushWildcardsFor(db, specs);
for (RefSpec spec : procRefs) {
+ if (spec.isMatching()) {
+ result.add(new RemoteRefUpdate(db, spec.isForceUpdate(),
+ fetchSpecs));
+ continue;
+ }
String srcSpec = spec.getSource();
final Ref srcRef = db.findRef(srcSpec);
if (srcRef != null)
@@ -656,14 +660,18 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
private static Collection<RefSpec> expandPushWildcardsFor(
final Repository db, final Collection<RefSpec> specs)
throws IOException {
- final List<Ref> localRefs = db.getRefDatabase().getRefs();
final Collection<RefSpec> procRefs = new LinkedHashSet<>();
+ List<Ref> localRefs = null;
for (RefSpec spec : specs) {
- if (spec.isWildcard()) {
+ if (!spec.isMatching() && spec.isWildcard()) {
+ if (localRefs == null) {
+ localRefs = db.getRefDatabase().getRefs();
+ }
for (Ref localRef : localRefs) {
- if (spec.matchSource(localRef))
+ if (spec.matchSource(localRef)) {
procRefs.add(spec.expandFromSource(localRef));
+ }
}
} else {
procRefs.add(spec);
@@ -672,7 +680,7 @@ private static Collection<RefSpec> expandPushWildcardsFor(
return procRefs;
}
- private static String findTrackingRefName(final String remoteName,
+ static String findTrackingRefName(final String remoteName,
final Collection<RefSpec> fetchSpecs) {
// try to find matching tracking refs
for (RefSpec fetchSpec : fetchSpecs) {
@@ -1371,16 +1379,9 @@ public PushResult push(final ProgressMonitor monitor,
if (toPush.isEmpty())
throw new TransportException(JGitText.get().nothingToPush);
}
- if (prePush != null) {
- try {
- prePush.setRefs(toPush);
- prePush.call();
- } catch (AbortedByHookException | IOException e) {
- throw new TransportException(e.getMessage(), e);
- }
- }
- final PushProcess pushProcess = new PushProcess(this, toPush, out);
+ final PushProcess pushProcess = new PushProcess(this, toPush, prePush,
+ out);
return pushProcess.execute(monitor);
}
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 6cb8fe4..1617c50 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -2358,7 +2358,7 @@ else if (ref.getName().startsWith(Constants.R_HEADS))
: req.getDepth() - 1;
pw.setShallowPack(req.getDepth(), unshallowCommits);
- @SuppressWarnings("resource") // Ownership is transferred below
+ // Ownership is transferred below
DepthWalk.RevWalk dw = new DepthWalk.RevWalk(
walk.getObjectReader(), walkDepth);
dw.setDeepenSince(req.getDeepenSince());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
index 3d15ef5..046f395 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010, Google Inc. and others
+ * Copyright (C) 2009-2022, Google Inc. and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -18,11 +18,11 @@
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.StringUtils;
/**
* Default resolver serving from the local filesystem.
@@ -67,7 +67,7 @@ public Repository open(C req, String name)
if (isUnreasonableName(name))
throw new RepositoryNotFoundException(name);
- Repository db = exports.get(nameWithDotGit(name));
+ Repository db = exports.get(StringUtils.nameWithDotGit(name));
if (db != null) {
db.incrementOpen();
return db;
@@ -154,7 +154,7 @@ public void setExportAll(boolean export) {
* the repository instance.
*/
public void exportRepository(String name, Repository db) {
- exports.put(nameWithDotGit(name), db);
+ exports.put(StringUtils.nameWithDotGit(name), db);
}
/**
@@ -197,12 +197,6 @@ else if (db.getDirectory() != null)
return false;
}
- private static String nameWithDotGit(String name) {
- if (name.endsWith(Constants.DOT_GIT_EXT))
- return name;
- return name + Constants.DOT_GIT_EXT;
- }
-
private static boolean isUnreasonableName(String name) {
if (name.length() == 0)
return true; // no empty paths
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 1f614e3..8269666 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2008-2009, Google Inc.
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2009 Google Inc.
+ * Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -14,6 +14,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -73,6 +74,7 @@
* threads.
*/
public class TreeWalk implements AutoCloseable, AttributesProvider {
+
private static final AbstractTreeIterator[] NO_TREES = {};
/**
@@ -92,7 +94,7 @@ public enum OperationType {
}
/**
- * Type of operation you want to retrieve the git attributes for.
+ * Type of operation you want to retrieve the git attributes for.
*/
private OperationType operationType = OperationType.CHECKOUT_OP;
@@ -284,11 +286,20 @@ public static TreeWalk forPath(final Repository db, final String path,
AbstractTreeIterator currentHead;
- /** Cached attribute for the current entry */
- private Attributes attrs = null;
+ /**
+ * Cached attributes for the current entry; per tree. Index i+1 is for tree
+ * i; index 0 is for the deprecated legacy behavior.
+ */
+ private Attributes[] attrs;
- /** Cached attributes handler */
- private AttributesHandler attributesHandler;
+ /**
+ * Cached attributes handler; per tree. Index i+1 is for tree i; index 0 is
+ * for the deprecated legacy behavior.
+ */
+ private AttributesHandler[] attributesHandlers;
+
+ /** Can be set to identify the tree to use for {@link #getAttributes()}. */
+ private int headIndex = -1;
private Config config;
@@ -515,6 +526,24 @@ public AttributesNodeProvider getAttributesNodeProvider() {
}
/**
+ * Identifies the tree at the given index as the head tree. This is the tree
+ * use by default to determine attributes and EOL modes.
+ *
+ * @param index
+ * of the tree to use as head
+ * @throws IllegalArgumentException
+ * if the index is out of range
+ * @since 6.1
+ */
+ public void setHead(int index) {
+ if (index < 0 || index >= trees.length) {
+ throw new IllegalArgumentException("Head index " + index //$NON-NLS-1$
+ + " out of range [0," + trees.length + ')'); //$NON-NLS-1$
+ }
+ headIndex = index;
+ }
+
+ /**
* {@inheritDoc}
* <p>
* Retrieve the git attributes for the current entry.
@@ -556,25 +585,51 @@ public AttributesNodeProvider getAttributesNodeProvider() {
*/
@Override
public Attributes getAttributes() {
- if (attrs != null)
- return attrs;
+ return getAttributes(headIndex);
+ }
+ /**
+ * Retrieves the git attributes based on the given tree.
+ *
+ * @param index
+ * of the tree to use as base for the attributes
+ * @return the attributes
+ * @since 6.1
+ */
+ public Attributes getAttributes(int index) {
+ int attrIndex = index + 1;
+ Attributes result = attrs[attrIndex];
+ if (result != null) {
+ return result;
+ }
if (attributesNodeProvider == null) {
- // The work tree should have a AttributesNodeProvider to be able to
- // retrieve the info and global attributes node
throw new IllegalStateException(
"The tree walk should have one AttributesNodeProvider set in order to compute the git attributes."); //$NON-NLS-1$
}
try {
- // Lazy create the attributesHandler on the first access of
- // attributes. This requires the info, global and root
- // attributes nodes
- if (attributesHandler == null) {
- attributesHandler = new AttributesHandler(this);
+ AttributesHandler handler = attributesHandlers[attrIndex];
+ if (handler == null) {
+ if (index < 0) {
+ // Legacy behavior (headIndex not set, getAttributes() above
+ // called)
+ handler = new AttributesHandler(this, () -> {
+ return getTree(CanonicalTreeParser.class);
+ });
+ } else {
+ handler = new AttributesHandler(this, () -> {
+ AbstractTreeIterator tree = trees[index];
+ if (tree instanceof CanonicalTreeParser) {
+ return (CanonicalTreeParser) tree;
+ }
+ return null;
+ });
+ }
+ attributesHandlers[attrIndex] = handler;
}
- attrs = attributesHandler.getAttributes();
- return attrs;
+ result = handler.getAttributes();
+ attrs[attrIndex] = result;
+ return result;
} catch (IOException e) {
throw new JGitInternalException("Error while parsing attributes", //$NON-NLS-1$
e);
@@ -595,11 +650,34 @@ public Attributes getAttributes() {
*/
@Nullable
public EolStreamType getEolStreamType(OperationType opType) {
- if (attributesNodeProvider == null || config == null)
+ if (attributesNodeProvider == null || config == null) {
return null;
- return EolStreamTypeUtil.detectStreamType(
- opType != null ? opType : operationType,
- config.get(WorkingTreeOptions.KEY), getAttributes());
+ }
+ OperationType op = opType != null ? opType : operationType;
+ return EolStreamTypeUtil.detectStreamType(op,
+ config.get(WorkingTreeOptions.KEY), getAttributes());
+ }
+
+ /**
+ * Get the EOL stream type of the current entry for checking out using the
+ * config and {@link #getAttributes()}.
+ *
+ * @param tree
+ * index of the tree the check-out is to be from
+ * @return the EOL stream type of the current entry using the config and
+ * {@link #getAttributes()}. Note that this method may return null
+ * if the {@link org.eclipse.jgit.treewalk.TreeWalk} is not based on
+ * a working tree
+ * @since 6.1
+ */
+ @Nullable
+ public EolStreamType getCheckoutEolStreamType(int tree) {
+ if (attributesNodeProvider == null || config == null) {
+ return null;
+ }
+ Attributes attr = getAttributes(tree);
+ return EolStreamTypeUtil.detectStreamType(OperationType.CHECKOUT_OP,
+ config.get(WorkingTreeOptions.KEY), attr);
}
/**
@@ -607,7 +685,8 @@ public EolStreamType getEolStreamType(OperationType opType) {
*/
public void reset() {
attrs = null;
- attributesHandler = null;
+ attributesHandlers = null;
+ headIndex = -1;
trees = NO_TREES;
advance = false;
depth = 0;
@@ -651,7 +730,9 @@ public void reset(AnyObjectId id) throws MissingObjectException,
advance = false;
depth = 0;
- attrs = null;
+ attrs = new Attributes[2];
+ attributesHandlers = new AttributesHandler[2];
+ headIndex = -1;
}
/**
@@ -701,7 +782,14 @@ public void reset(AnyObjectId... ids) throws MissingObjectException,
trees = r;
advance = false;
depth = 0;
- attrs = null;
+ if (oldLen == newLen) {
+ Arrays.fill(attrs, null);
+ Arrays.fill(attributesHandlers, null);
+ } else {
+ attrs = new Attributes[newLen + 1];
+ attributesHandlers = new AttributesHandler[newLen + 1];
+ }
+ headIndex = -1;
}
/**
@@ -758,6 +846,16 @@ public int addTree(AbstractTreeIterator p) {
p.matchShift = 0;
trees = newTrees;
+ if (attrs == null) {
+ attrs = new Attributes[n + 2];
+ } else {
+ attrs = Arrays.copyOf(attrs, n + 2);
+ }
+ if (attributesHandlers == null) {
+ attributesHandlers = new AttributesHandler[n + 2];
+ } else {
+ attributesHandlers = Arrays.copyOf(attributesHandlers, n + 2);
+ }
return n;
}
@@ -800,7 +898,7 @@ public boolean next() throws MissingObjectException,
}
for (;;) {
- attrs = null;
+ Arrays.fill(attrs, null);
final AbstractTreeIterator t = min();
if (t.eof()) {
if (depth > 0) {
@@ -1255,7 +1353,7 @@ public boolean isPostChildren() {
*/
public void enterSubtree() throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
- attrs = null;
+ Arrays.fill(attrs, null);
final AbstractTreeIterator ch = currentHead;
final AbstractTreeIterator[] tmp = new AbstractTreeIterator[trees.length];
for (int i = 0; i < trees.length; i++) {
@@ -1374,11 +1472,12 @@ public <T extends AbstractTreeIterator> T getTree(Class<T> type) {
/**
* Inspect config and attributes to return a filtercommand applicable for
- * the current path, but without expanding %f occurences
+ * the current path.
*
* @param filterCommandType
* which type of filterCommand should be executed. E.g. "clean",
- * "smudge"
+ * "smudge". For "smudge" consider using
+ * {{@link #getSmudgeCommand(int)} instead.
* @return a filter command
* @throws java.io.IOException
* @since 4.2
@@ -1407,6 +1506,54 @@ public String getFilterCommand(String filterCommandType)
}
/**
+ * Inspect config and attributes to return a filtercommand applicable for
+ * the current path.
+ *
+ * @param index
+ * of the tree the item to be smudged is in
+ * @return a filter command
+ * @throws java.io.IOException
+ * @since 6.1
+ */
+ public String getSmudgeCommand(int index)
+ throws IOException {
+ return getSmudgeCommand(getAttributes(index));
+ }
+
+ /**
+ * Inspect config and attributes to return a filtercommand applicable for
+ * the current path.
+ *
+ * @param attributes
+ * to use
+ * @return a filter command
+ * @throws java.io.IOException
+ * @since 6.1
+ */
+ public String getSmudgeCommand(Attributes attributes) throws IOException {
+ if (attributes == null) {
+ return null;
+ }
+ Attribute f = attributes.get(Constants.ATTR_FILTER);
+ if (f == null) {
+ return null;
+ }
+ String filterValue = f.getValue();
+ if (filterValue == null) {
+ return null;
+ }
+
+ String filterCommand = getFilterCommandDefinition(filterValue,
+ Constants.ATTR_FILTER_TYPE_SMUDGE);
+ if (filterCommand == null) {
+ return null;
+ }
+ return filterCommand.replaceAll("%f", //$NON-NLS-1$
+ Matcher.quoteReplacement(
+ QuotedString.BOURNE.quote((getPathString()))));
+ }
+
+ /**
* Get the filter command how it is defined in gitconfig. The returned
* string may contain "%f" which needs to be replaced by the current path
* before executing the filter command. These filter definitions are cached
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 50ce15e..427eac5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -2,7 +2,7 @@
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
* Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
- * Copyright (C) 2012-2021, Robin Rosenberg and others
+ * Copyright (C) 2012, 2022, Robin Rosenberg and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -387,8 +387,8 @@ public boolean isWorkTree() {
state.initializeReadBuffer();
final long len = e.getLength();
- InputStream filteredIs = possiblyFilteredInputStream(e, is, len,
- OperationType.CHECKIN_OP);
+ InputStream filteredIs = possiblyFilteredInputStream(e, is,
+ len);
return computeHash(filteredIs, canonLen);
} finally {
safeClose(is);
@@ -400,23 +400,18 @@ public boolean isWorkTree() {
}
private InputStream possiblyFilteredInputStream(final Entry e,
- final InputStream is, final long len) throws IOException {
- return possiblyFilteredInputStream(e, is, len, null);
-
- }
-
- private InputStream possiblyFilteredInputStream(final Entry e,
- final InputStream is, final long len, OperationType opType)
+ final InputStream is, final long len)
throws IOException {
if (getCleanFilterCommand() == null
- && getEolStreamType(opType) == EolStreamType.DIRECT) {
+ && getEolStreamType(
+ OperationType.CHECKIN_OP) == EolStreamType.DIRECT) {
canonLen = len;
return is;
}
if (len <= MAXIMUM_FILE_SIZE_TO_READ_FULLY) {
ByteBuffer rawbuf = IO.readWholeStream(is, (int) len);
- rawbuf = filterClean(rawbuf.array(), rawbuf.limit(), opType);
+ rawbuf = filterClean(rawbuf.array(), rawbuf.limit());
canonLen = rawbuf.limit();
return new ByteArrayInputStream(rawbuf.array(), 0, (int) canonLen);
}
@@ -426,14 +421,13 @@ && getEolStreamType(opType) == EolStreamType.DIRECT) {
return is;
}
- final InputStream lenIs = filterClean(e.openInputStream(),
- opType);
+ final InputStream lenIs = filterClean(e.openInputStream());
try {
canonLen = computeLength(lenIs);
} finally {
safeClose(lenIs);
}
- return filterClean(is, opType);
+ return filterClean(is);
}
private static void safeClose(InputStream in) {
@@ -455,23 +449,20 @@ private static boolean isBinary(Entry entry) throws IOException {
}
}
- private ByteBuffer filterClean(byte[] src, int n, OperationType opType)
+ private ByteBuffer filterClean(byte[] src, int n)
throws IOException {
InputStream in = new ByteArrayInputStream(src);
try {
- return IO.readWholeStream(filterClean(in, opType), n);
+ return IO.readWholeStream(filterClean(in), n);
} finally {
safeClose(in);
}
}
- private InputStream filterClean(InputStream in) throws IOException {
- return filterClean(in, null);
- }
-
- private InputStream filterClean(InputStream in, OperationType opType)
+ private InputStream filterClean(InputStream in)
throws IOException {
- in = handleAutoCRLF(in, opType);
+ in = EolStreamTypeUtil.wrapInputStream(in,
+ getEolStreamType(OperationType.CHECKIN_OP));
String filterCommand = getCleanFilterCommand();
if (filterCommand != null) {
if (FilterCommandRegistry.isRegistered(filterCommand)) {
@@ -509,11 +500,6 @@ filterCommand, getEntryPathString(),
return in;
}
- private InputStream handleAutoCRLF(InputStream in, OperationType opType)
- throws IOException {
- return EolStreamTypeUtil.wrapInputStream(in, getEolStreamType(opType));
- }
-
/**
* Returns the working tree options used by this iterator.
*
@@ -664,7 +650,8 @@ public Instant getEntryLastModifiedInstant() {
public InputStream openEntryStream() throws IOException {
InputStream rawis = current().openInputStream();
if (getCleanFilterCommand() == null
- && getEolStreamType() == EolStreamType.DIRECT) {
+ && getEolStreamType(
+ OperationType.CHECKIN_OP) == EolStreamType.DIRECT) {
return rawis;
}
return filterClean(rawis);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
index ff094f6..ae73d3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
@@ -16,6 +16,7 @@
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
+import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
@@ -96,6 +97,9 @@ public boolean retryFailedLockFileCommit() {
/** {@inheritDoc} */
@Override
public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
+ if (!Files.isDirectory(directory.toPath(), LinkOption.NOFOLLOW_LINKS)) {
+ return NO_ENTRIES;
+ }
List<Entry> result = new ArrayList<>();
FS fs = this;
boolean checkExecutable = fs.supportsExecute();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
index 8ab1338..917add3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010, Google Inc. and others
+ * Copyright (C) 2009-2022, Google Inc. and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -15,6 +15,7 @@
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
/**
* Miscellaneous string comparison utility methods.
@@ -37,6 +38,10 @@ public final class StringUtils {
LC[c] = (char) ('a' + (c - 'A'));
}
+ private StringUtils() {
+ // Do not create instances
+ }
+
/**
* Convert the input to lowercase.
* <p>
@@ -269,8 +274,20 @@ public static String join(Collection<String> parts, String separator,
return sb.toString();
}
- private StringUtils() {
- // Do not create instances
+ /**
+ * Appends {@link Constants#DOT_GIT_EXT} unless the given name already ends
+ * with that suffix.
+ *
+ * @param name
+ * to complete
+ * @return the name ending with {@link Constants#DOT_GIT_EXT}
+ * @since 6.1
+ */
+ public static String nameWithDotGit(String name) {
+ if (name.endsWith(Constants.DOT_GIT_EXT)) {
+ return name;
+ }
+ return name + Constants.DOT_GIT_EXT;
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/BinaryHunkInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/BinaryHunkInputStream.java
index 4f940d7..2c972b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/BinaryHunkInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/BinaryHunkInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2021, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -90,7 +90,7 @@ private void fillBuffer() throws IOException {
byte[] encoded = new byte[Base85.encodedLength(length)];
for (int i = 0; i < encoded.length; i++) {
int b = in.read();
- if (b < 0 || b == '\n') {
+ if (b < 0 || b == '\r' || b == '\n') {
throw new EOFException(MessageFormat.format(
JGitText.get().binaryHunkInvalidLength,
Integer.valueOf(lineNumber)));
@@ -99,6 +99,10 @@ private void fillBuffer() throws IOException {
}
// Must be followed by a newline; tolerate EOF.
int b = in.read();
+ if (b == '\r') {
+ // Be lenient and accept CR-LF, too.
+ b = in.read();
+ }
if (b >= 0 && b != '\n') {
throw new StreamCorruptedException(MessageFormat.format(
JGitText.get().binaryHunkMissingNewline,
diff --git a/pom.xml b/pom.xml
index c486569..81093c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,7 +18,7 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
<packaging>pom</packaging>
- <version>6.0.1-SNAPSHOT</version>
+ <version>6.1.1-SNAPSHOT</version>
<name>JGit - Parent</name>
<url>${jgit-url}</url>
@@ -150,9 +150,9 @@
<java.version>11</java.version>
<bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
- <jgit-last-release-version>5.13.0.202109080827-r</jgit-last-release-version>
+ <jgit-last-release-version>6.0.0.202111291000-r</jgit-last-release-version>
<ant-version>1.10.12</ant-version>
- <apache-sshd-version>2.7.0</apache-sshd-version>
+ <apache-sshd-version>2.8.0</apache-sshd-version>
<jsch-version>0.1.55</jsch-version>
<jzlib-version>1.1.1</jzlib-version>
<javaewah-version>1.1.13</javaewah-version>
@@ -160,7 +160,7 @@
<test-fork-count>1C</test-fork-count>
<args4j-version>2.33</args4j-version>
<commons-compress-version>1.21</commons-compress-version>
- <osgi-core-version>4.3.1</osgi-core-version>
+ <osgi-core-version>6.0.0</osgi-core-version>
<servlet-api-version>4.0.0</servlet-api-version>
<jetty-version>10.0.6</jetty-version>
<japicmp-version>0.15.3</japicmp-version>
@@ -169,8 +169,8 @@
<slf4j-version>1.7.30</slf4j-version>
<maven-javadoc-plugin-version>3.3.1</maven-javadoc-plugin-version>
<tycho-extras-version>2.5.0</tycho-extras-version>
- <gson-version>2.8.8</gson-version>
- <bouncycastle-version>1.69</bouncycastle-version>
+ <gson-version>2.8.9</gson-version>
+ <bouncycastle-version>1.70</bouncycastle-version>
<spotbugs-maven-plugin-version>4.3.0</spotbugs-maven-plugin-version>
<maven-project-info-reports-plugin-version>3.1.2</maven-project-info-reports-plugin-version>
<maven-jxr-plugin-version>3.1.1</maven-jxr-plugin-version>
@@ -203,6 +203,14 @@
<id>repo.eclipse.org.cbi-snapshots</id>
<url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url>
</pluginRepository>
+ <pluginRepository>
+ <id>repo.eclipse.org.dash-releases</id>
+ <url>https://repo.eclipse.org/content/repositories/dash-licenses-releases/</url>
+ </pluginRepository>
+ <pluginRepository>
+ <id>repo.eclipse.org.dash-snapshots</id>
+ <url>https://repo.eclipse.org/content/repositories/dash-licenses-snapshots/</url>
+ </pluginRepository>
</pluginRepositories>
<build>
@@ -338,7 +346,7 @@
<dependency><!-- add support for ssh/scp -->
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
- <version>3.4.3</version>
+ <version>3.5.1</version>
</dependency>
</dependencies>
</plugin>
@@ -382,6 +390,11 @@
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.4</version>
</plugin>
+ <plugin>
+ <groupId>org.eclipse.dash</groupId>
+ <artifactId>license-tool-plugin</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </plugin>
</plugins>
</pluginManagement>
@@ -540,6 +553,10 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
</plugin>
+ <plugin>
+ <groupId>org.eclipse.dash</groupId>
+ <artifactId>license-tool-plugin</artifactId>
+ </plugin>
</plugins>
</build>
@@ -853,7 +870,7 @@
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
- <version>3.27.0</version>
+ <version>3.28.0</version>
</dependency>
</dependencies>
</plugin>
diff --git a/tools/BUILD b/tools/BUILD
index 0c6b8ec..a109019 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -1,34 +1,28 @@
load(
"@bazel_tools//tools/jdk:default_java_toolchain.bzl",
- "JDK9_JVM_OPTS",
"default_java_toolchain",
)
load("@rules_java//java:defs.bzl", "java_package_configuration")
-JDK11_JVM_OPTS = [
- "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
- "--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
- "--patch-module=java.compiler=$(location @bazel_tools//tools/jdk:java_compiler_jar)",
- "--patch-module=jdk.compiler=$(location @bazel_tools//tools/jdk:jdk_compiler_jar)",
- "--add-opens=java.base/java.nio=ALL-UNNAMED",
- "--add-opens=java.base/java.lang=ALL-UNNAMED",
-]
-
default_java_toolchain(
- name = "error_prone_warnings_toolchain",
- bootclasspath = ["@bazel_tools//tools/jdk:platformclasspath.jar"],
- jvm_opts = JDK11_JVM_OPTS,
- source_version = "11",
- target_version = "11",
+ name = "error_prone_warnings_toolchain_java11",
package_configuration = [
":error_prone",
],
+ source_version = "11",
+ target_version = "11",
+ visibility = ["//visibility:public"],
+)
+
+default_java_toolchain(
+ name = "error_prone_warnings_toolchain_java17",
+ configuration = dict(),
+ java_runtime = "@bazel_tools//tools/jdk:remotejdk_17",
+ package_configuration = [
+ ":error_prone",
+ ],
+ source_version = "17",
+ target_version = "17",
visibility = ["//visibility:public"],
)
@@ -108,20 +102,25 @@
"//org.eclipse.jgit.ant.test/...",
"//org.eclipse.jgit.ant/...",
"//org.eclipse.jgit.archive/...",
+ "//org.eclipse.jgit.gpg.bc.test/...",
+ "//org.eclipse.jgit.gpg.bc/...",
"//org.eclipse.jgit.http.apache/...",
"//org.eclipse.jgit.http.server/...",
"//org.eclipse.jgit.http.test/...",
- "//org.eclipse.jgit.junit.http/...",
+ "//org.eclipse.jgit.junit.ssh/...",
"//org.eclipse.jgit.junit/...",
+ "//org.eclipse.jgit.junit/http/...",
"//org.eclipse.jgit.lfs.server.test/...",
"//org.eclipse.jgit.lfs.server/...",
"//org.eclipse.jgit.lfs.test/...",
"//org.eclipse.jgit.lfs/...",
- "//org.eclipse.jgit.packaging/...",
"//org.eclipse.jgit.pgm.test/...",
"//org.eclipse.jgit.pgm/...",
- "//org.eclipse.jgit.ssh.apache/...",
"//org.eclipse.jgit.ssh.apache.agent/...",
+ "//org.eclipse.jgit.ssh.apache.test/...",
+ "//org.eclipse.jgit.ssh.apache/...",
+ "//org.eclipse.jgit.ssh.jsch.test/...",
+ "//org.eclipse.jgit.ssh.jsch/...",
"//org.eclipse.jgit.test/...",
"//org.eclipse.jgit.ui/...",
"//org.eclipse.jgit/...",
diff --git a/tools/bazelisk_version.bzl b/tools/bazelisk_version.bzl
deleted file mode 100644
index d8b3d10..0000000
--- a/tools/bazelisk_version.bzl
+++ /dev/null
@@ -1,16 +0,0 @@
-_template = """
-load("@bazel_skylib//lib:versions.bzl", "versions")
-
-def check_bazel_version():
- versions.check(minimum_bazel_version = "{version}")
-""".strip()
-
-def _impl(repository_ctx):
- repository_ctx.symlink(Label("@//:.bazelversion"), ".bazelversion")
- bazelversion = repository_ctx.read(".bazelversion").strip()
-
- repository_ctx.file("BUILD", executable = False)
-
- repository_ctx.file("check.bzl", executable = False, content = _template.format(version = bazelversion))
-
-bazelisk_version = repository_rule(implementation = _impl)
diff --git a/tools/remote-bazelrc b/tools/remote-bazelrc
new file mode 100644
index 0000000..58f794e
--- /dev/null
+++ b/tools/remote-bazelrc
@@ -0,0 +1,67 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is auto-generated from release/bazelrc.tpl and should not be
+# modified directly.
+
+# This .bazelrc file contains all of the flags required for the provided
+# toolchain with Remote Build Execution.
+#
+# This .bazelrc file also contains all of the flags required for the local
+# docker sandboxing.
+
+# Depending on how many machines are in the remote execution instance, setting
+# this higher can make builds faster by allowing more jobs to run in parallel.
+# Setting it too high can result in jobs that timeout, however, while waiting
+# for a remote machine to execute them.
+build:remote --jobs=200
+build:remote --disk_cache=
+
+# Set several flags related to specifying the platform, toolchain and java
+# properties.
+build:remote --host_javabase=@rbe_jdk11//java:jdk
+build:remote --javabase=@rbe_jdk11//java:jdk
+build:remote --crosstool_top=@rbe_jdk11//cc:toolchain
+build:remote --extra_toolchains=@rbe_jdk11//config:cc-toolchain
+build:remote --extra_execution_platforms=@rbe_jdk11//config:platform
+build:remote --host_platform=@rbe_jdk11//config:platform
+build:remote --platforms=@rbe_jdk11//config:platform
+build:remote --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1
+
+# Set various strategies so that all actions execute remotely. Mixing remote
+# and local execution will lead to errors unless the toolchain and remote
+# machine exactly match the host machine.
+build:remote --define=EXECUTOR=remote
+
+# Enable the remote cache so action results can be shared across machines,
+# developers, and workspaces.
+build:remote --remote_cache=remotebuildexecution.googleapis.com
+
+# Enable remote execution so actions are performed on the remote systems.
+build:remote --remote_executor=remotebuildexecution.googleapis.com
+
+# Set a higher timeout value, just in case.
+build:remote --remote_timeout=3600
+
+# Enable authentication. This will pick up application default credentials by
+# default. You can use --auth_credentials=some_file.json to use a service
+# account credential instead.
+build:remote --google_default_credentials
+
+# The following flags enable the remote cache so action results can be shared
+# across machines, developers, and workspaces.
+build:remote-cache --remote_cache=remotebuildexecution.googleapis.com
+build:remote-cache --tls_enabled=true
+build:remote-cache --remote_timeout=3600
+build:remote-cache --auth_enabled=true