summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPENDENCIES52
-rw-r--r--WORKSPACE4
-rw-r--r--org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF10
-rw-r--r--org.eclipse.jgit.ant.test/pom.xml2
-rw-r--r--org.eclipse.jgit.ant/META-INF/MANIFEST.MF8
-rw-r--r--org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.ant/pom.xml2
-rw-r--r--org.eclipse.jgit.archive/META-INF/MANIFEST.MF16
-rw-r--r--org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.archive/pom.xml2
-rw-r--r--org.eclipse.jgit.benchmarks/pom.xml2
-rw-r--r--org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java181
-rw-r--r--org.eclipse.jgit.coverage/pom.xml36
-rw-r--r--org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF8
-rw-r--r--org.eclipse.jgit.gpg.bc.test/pom.xml2
-rw-r--r--org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF14
-rw-r--r--org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.gpg.bc/pom.xml2
-rw-r--r--org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF12
-rw-r--r--org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.http.apache/pom.xml2
-rw-r--r--org.eclipse.jgit.http.server/META-INF/MANIFEST.MF30
-rw-r--r--org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.http.server/pom.xml2
-rw-r--r--org.eclipse.jgit.http.test/META-INF/MANIFEST.MF42
-rw-r--r--org.eclipse.jgit.http.test/pom.xml2
-rw-r--r--org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF20
-rw-r--r--org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.junit.http/pom.xml2
-rw-r--r--org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF22
-rw-r--r--org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.junit.ssh/pom.xml2
-rw-r--r--org.eclipse.jgit.junit/META-INF/MANIFEST.MF40
-rw-r--r--org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.junit/pom.xml2
-rw-r--r--org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF38
-rw-r--r--org.eclipse.jgit.lfs.server.test/pom.xml2
-rw-r--r--org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF32
-rw-r--r--org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.lfs.server/pom.xml2
-rw-r--r--org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF34
-rw-r--r--org.eclipse.jgit.lfs.test/pom.xml2
-rw-r--r--org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/LfsConfigGitTest.java8
-rw-r--r--org.eclipse.jgit.lfs/META-INF/MANIFEST.MF49
-rw-r--r--org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.lfs/pom.xml2
-rw-r--r--org.eclipse.jgit.lfs/resources/org/eclipse/jgit/lfs/internal/LfsText.properties5
-rw-r--r--org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java8
-rw-r--r--org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java62
-rw-r--r--org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsText.java1
-rw-r--r--org.eclipse.jgit.packaging/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target20
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target20
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target20
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target20
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target20
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target20
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target97
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target97
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd69
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml29
-rw-r--r--org.eclipse.jgit.packaging/pom.xml11
-rw-r--r--org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF42
-rw-r--r--org.eclipse.jgit.pgm.test/pom.xml2
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java361
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java395
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java243
-rw-r--r--org.eclipse.jgit.pgm/META-INF/MANIFEST.MF86
-rw-r--r--org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin1
-rw-r--r--org.eclipse.jgit.pgm/pom.xml2
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties29
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java257
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java475
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java20
-rw-r--r--org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF13
-rw-r--r--org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.ssh.apache.agent/pom.xml2
-rw-r--r--org.eclipse.jgit.ssh.apache.agent/src/org/eclipse/jgit/internal/transport/sshd/agent/connector/WinPipeConnector.java2
-rw-r--r--org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF22
-rw-r--r--org.eclipse.jgit.ssh.apache.test/pom.xml2
-rw-r--r--org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java74
-rw-r--r--org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF30
-rw-r--r--org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.ssh.apache/pom.xml12
-rw-r--r--org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties17
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationLogger.java238
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java60
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthentication.java33
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthenticationReporter.java93
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java33
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java7
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java21
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java19
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java33
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java19
-rw-r--r--org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF16
-rw-r--r--org.eclipse.jgit.ssh.jsch.test/pom.xml2
-rw-r--r--org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF20
-rw-r--r--org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.ssh.jsch/pom.xml2
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF112
-rw-r--r--org.eclipse.jgit.test/pom.xml2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java47
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java16
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java68
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java96
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java371
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java433
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java54
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java79
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java48
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java229
-rw-r--r--org.eclipse.jgit.ui/META-INF/MANIFEST.MF18
-rw-r--r--org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.ui/pom.xml2
-rw-r--r--org.eclipse.jgit/META-INF/MANIFEST.MF110
-rw-r--r--org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit/pom.xml2
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java40
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java83
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java77
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java25
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandExecutor.java239
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java327
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java323
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalDiffTool.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java33
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java242
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java262
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/InformNoToolHandler.java28
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java147
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java452
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java91
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PromptContinueHandler.java27
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java139
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java19
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java69
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFileSnapshot.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java109
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BaseSearch.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java104
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java48
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java49
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java44
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java69
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java72
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java15
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java41
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java74
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java50
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java44
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UrlConfig.java120
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java36
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java94
-rw-r--r--pom.xml8
206 files changed, 8136 insertions, 1342 deletions
diff --git a/DEPENDENCIES b/DEPENDENCIES
index 93fa850d8a..be7ab17cb4 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -2,10 +2,10 @@ maven/mavencentral/args4j/args4j/2.33, MIT, approved, CQ11068
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/com.jcraft/jzlib/1.1.3, 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/4.0.0, , approved, CQ16125
+maven/mavencentral/javax.servlet/javax.servlet-api/4.0.0, (CDDL-1.1 OR GPL-2.0-only WITH Classpath-exception-2.0) AND Apache-2.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
@@ -19,6 +19,8 @@ maven/mavencentral/org.apache.commons/commons-compress/1.21, Apache-2.0 AND BSD-
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.8.0, Apache-2.0 AND ISC, approved, #2349
+maven/mavencentral/org.apache.sshd/sshd-core/2.8.0, Apache-2.0, approved, #2331
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
@@ -33,29 +35,29 @@ maven/mavencentral/org.eclipse.jetty/jetty-security/10.0.6, EPL-2.0 OR Apache-2.
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.eclipse.jgit/org.eclipse.jgit.ant.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.archive/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.gpg.bc/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.apache/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.server/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.http/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.ssh/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.agent/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.jsch/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.test/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ui/6.2.0-SNAPSHOT, BSD-3-Clause, approved, technology.jgit
+maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit/6.2.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
diff --git a/WORKSPACE b/WORKSPACE
index 040617e8a6..cce13164ef 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -68,8 +68,8 @@ maven_jar(
maven_jar(
name = "jzlib",
- artifact = "com.jcraft:jzlib:1.1.1",
- sha1 = "a1551373315ffc2f96130a0e5704f74e151777ba",
+ artifact = "com.jcraft:jzlib:1.1.3",
+ sha1 = "c01428efa717624f7aabf4df319939dda9646b2d",
)
maven_jar(
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 09975705df..e4d990cb5d 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 @@ Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ant.test
Bundle-SymbolicName: org.eclipse.jgit.ant.test
Bundle-Vendor: %Bundle-Vendor
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: org.apache.tools.ant,
- 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.eclipse.jgit.ant.tasks;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 ba473eff29..724708674b 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 6003a31e86..066da0781f 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ant
Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)"
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)"
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.ant;version="6.1.1",
- org.eclipse.jgit.ant.tasks;version="6.1.1";
+Export-Package: org.eclipse.jgit.ant;version="6.2.0",
+ org.eclipse.jgit.ant.tasks;version="6.2.0";
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 d0dc5c8dd1..3cde5928f2 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.ant - Sources
Bundle-SymbolicName: org.eclipse.jgit.ant.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ant;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ant;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index a7f258be53..75b17178ce 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 3fc8df1229..f5125de75c 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.archive
Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -13,17 +13,17 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.4,2.0)",
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.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.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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.1.1";
+Export-Package: org.eclipse.jgit.archive;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.api,
org.apache.commons.compress.archivers,
org.osgi.framework",
- org.eclipse.jgit.archive.internal;version="6.1.1";x-internal:=true
+ org.eclipse.jgit.archive.internal;version="6.2.0";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 8c7fd07200..5dfc65958c 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.archive - Sources
Bundle-SymbolicName: org.eclipse.jgit.archive.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 12f3e685d8..e4f2d67120 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 0f72f64ff6..c8b088726d 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
<artifactId>org.eclipse.jgit.benchmarks</artifactId>
<packaging>jar</packaging>
diff --git a/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java
new file mode 100644
index 0000000000..62627e66f6
--- /dev/null
+++ b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2021, Luca Milanesio <luca.milanesio@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.benchmarks;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.lib.*;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FileUtils;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.CREATE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE;
+
+@State(Scope.Thread)
+public class GetRefsBenchmark {
+
+ ThreadLocalRandom branchIndex = ThreadLocalRandom.current();
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkState {
+
+ @Param({ "true", "false" })
+ boolean useRefTable;
+
+ @Param({ "100", "2500", "10000", "50000" })
+ int numBranches;
+
+ @Param({ "true", "false" })
+ boolean trustFolderStat;
+
+ List<String> branches = new ArrayList<>(numBranches);
+
+ Path testDir;
+
+ Repository repo;
+
+ @Setup
+ @SuppressWarnings("boxing")
+ public void setupBenchmark() throws IOException, GitAPIException {
+ String firstBranch = "firstbranch";
+ testDir = Files.createDirectory(Paths.get("testrepos"));
+ String repoName = "branches-" + numBranches + "-trustFolderStat-"
+ + trustFolderStat + "-" + refDatabaseType();
+ Path workDir = testDir.resolve(repoName);
+ Path repoPath = workDir.resolve(".git");
+ Git git = Git.init().setDirectory(workDir.toFile()).call();
+ RevCommit firstCommit = git.commit().setMessage("First commit")
+ .call();
+ git.branchCreate().setName(firstBranch).call();
+
+ StoredConfig cfg = git.getRepository().getConfig();
+ if (useRefTable) {
+ ((FileRepository) git.getRepository()).convertRefStorage(
+ ConfigConstants.CONFIG_REF_STORAGE_REFTABLE, false,
+ false);
+ } else {
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT,
+ trustFolderStat);
+ }
+ cfg.setInt(ConfigConstants.CONFIG_RECEIVE_SECTION, null,
+ "maxCommandBytes", Integer.MAX_VALUE);
+ cfg.save();
+
+ repo = RepositoryCache.open(RepositoryCache.FileKey
+ .lenient(repoPath.toFile(), FS.DETECTED));
+
+ System.out.println("Preparing test");
+ System.out.println("- repository: \t\t" + repoPath);
+ System.out.println("- refDatabase: \t\t" + refDatabaseType());
+ System.out.println("- trustFolderStat: \t" + trustFolderStat);
+ System.out.println("- branches: \t\t" + numBranches);
+
+ BatchRefUpdate u = repo.getRefDatabase().newBatchUpdate();
+
+ branches = IntStream.range(0, numBranches)
+ .mapToObj(i -> "branch/" + i % 100 + "/" + i)
+ .collect(Collectors.toList());
+ for (String branch : branches) {
+ u.addCommand(new ReceiveCommand(ObjectId.zeroId(),
+ firstCommit.toObjectId(), Constants.R_HEADS + branch,
+ CREATE));
+ }
+
+ System.out.println();
+ System.out.print(
+ String.format("Creating %d branches ... ", numBranches));
+
+ try (RevWalk rw = new RevWalk(repo)) {
+ u.execute(rw, new TextProgressMonitor());
+ }
+ System.out.println("DONE");
+ }
+
+ private String refDatabaseType() {
+ return useRefTable ? "reftable" : "refdir";
+ }
+
+ @TearDown
+ public void teardown() throws IOException {
+ repo.close();
+ FileUtils.delete(testDir.toFile(),
+ FileUtils.RECURSIVE | FileUtils.RETRY);
+ }
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.AverageTime })
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.SECONDS)
+ public void testGetExactRef(Blackhole blackhole, BenchmarkState state)
+ throws IOException {
+ String branchName = state.branches
+ .get(branchIndex.nextInt(state.numBranches));
+ blackhole.consume(state.repo.exactRef(branchName));
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.AverageTime })
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.SECONDS)
+ public void testGetRefsByPrefix(Blackhole blackhole, BenchmarkState state)
+ throws IOException {
+ String branchPrefix = "refs/heads/branch/" + branchIndex.nextInt(100)
+ + "/";
+ blackhole.consume(
+ state.repo.getRefDatabase().getRefsByPrefix(branchPrefix));
+ }
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(GetRefsBenchmark.class.getSimpleName())
+ // .addProfiler(StackProfiler.class)
+ // .addProfiler(GCProfiler.class)
+ .forks(1).jvmArgs("-ea").build();
+ new Runner(opt).run();
+ }
+}
diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml
index abc37ec69f..a99e23e05b 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ant</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.archive</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.server</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs.server</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.pgm</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ui</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.ssh.apache.test</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
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 bb9b393f87..c92fd3e41f 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.gpg.bc.test
Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -12,9 +12,9 @@ Import-Package: org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)",
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.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.eclipse.jgit.gpg.bc.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.sha1;version="[6.2.0,6.3.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 9568c6884d..2556889e3e 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 534568dd80..fb45761616 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-ManifestVersion: 2
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.1.1,6.2.0)"
+Fragment-Host: org.eclipse.jgit;bundle-version="[6.2.0,6.3.0)"
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.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 @@ Import-Package: org.bouncycastle.asn1;version="[1.69.0,2.0.0)",
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.1.1,6.2.0)",
- org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
org.slf4j;version="[1.7.0,2.0.0)"
-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"
+Export-Package: org.eclipse.jgit.gpg.bc;version="6.2.0",
+ org.eclipse.jgit.gpg.bc.internal;version="6.2.0";x-friends:="org.eclipse.jgit.gpg.bc.test",
+ org.eclipse.jgit.gpg.bc.internal.keys;version="6.2.0";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 20e2d01de1..b62a2a66f2 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.gpg.bc - Sources
Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml
index 138f4e8a4b..69465d0917 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 afcaa78d57..df60729a87 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.http.apache
Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
@@ -25,11 +25,11 @@ Import-Package: org.apache.http;version="[4.3.0,5.0.0)",
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.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";
+ org.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="6.2.0";
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 7b8e1497eb..ead725643f 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.http.apache - Sources
Bundle-SymbolicName: org.eclipse.jgit.http.apache.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index bd35589f54..0bd899f391 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 4bf66a2e97..cd7db79e92 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.http.server
Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.http.server;version="6.1.1",
- org.eclipse.jgit.http.server.glue;version="6.1.1";
+Export-Package: org.eclipse.jgit.http.server;version="6.2.0",
+ org.eclipse.jgit.http.server.glue;version="6.2.0";
uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="6.1.1";
+ org.eclipse.jgit.http.server.resolver;version="6.2.0";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.lib,
org.eclipse.jgit.transport,
@@ -18,14 +18,14 @@ Bundle-ActivationPolicy: lazy
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.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)"
+ org.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 2b47055232..b86561af0b 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.http.server - Sources
Bundle-SymbolicName: org.eclipse.jgit.http.server.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 6a788e2323..2ea4c6a344 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index 4150bdb403..1b8caed708 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.http.test
Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -26,26 +26,26 @@ Import-Package: javax.servlet;version="[2.5.0,5.0.0)",
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.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.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.http.server;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.http.server.glue;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.http.server.resolver;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 336f43bfff..7a7b409cee 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index d035072b5b..50e814b404 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.junit.http
Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
@@ -21,17 +21,17 @@ Import-Package: javax.servlet;version="[2.5.0,5.0.0)",
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.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.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.http.server;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.2.0,6.3.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.1.1";
+Export-Package: org.eclipse.jgit.junit.http;version="6.2.0";
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 19142c51fd..da1714281e 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.junit.http - Sources
Bundle-SymbolicName: org.eclipse.jgit.junit.http.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index d883e03879..440a06cdb4 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 60858d8c01..8caf93ab8a 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.junit.ssh
Bundle-SymbolicName: org.eclipse.jgit.junit.ssh
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
@@ -33,16 +33,16 @@ Import-Package: org.apache.sshd.common;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.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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.1.1"
+Export-Package: org.eclipse.jgit.junit.ssh;version="6.2.0"
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 41246bcee9..f6f2c2d582 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.junit.ssh - Sources
Bundle-SymbolicName: org.eclipse.jgit.junit.ssh.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index 07d0218bf4..395b14b0a1 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.ssh</artifactId>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 7a3b200e17..209b232303 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,35 +3,35 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.junit
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
-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)",
+Import-Package: org.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.dircache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.merge;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="6.2.0",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.time;version="[6.2.0,6.3.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.1.1";
+Export-Package: org.eclipse.jgit.junit;version="6.2.0";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
@@ -44,4 +44,4 @@ Export-Package: org.eclipse.jgit.junit;version="6.1.1";
org.junit.runners.model,
org.junit.runner,
org.eclipse.jgit.util.time",
- org.eclipse.jgit.junit.time;version="6.1.1";uses:="org.eclipse.jgit.util.time"
+ org.eclipse.jgit.junit.time;version="6.2.0";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 25876c7fc7..f1dad6a839 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.junit - Sources
Bundle-SymbolicName: org.eclipse.jgit.junit.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.junit;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.junit;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index 2c260e2475..13bb6a7458 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit</artifactId>
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 cbb8135d77..23078bdc83 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs.server.test
Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -26,24 +26,24 @@ Import-Package: javax.servlet;version="[3.1.0,5.0.0)",
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.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.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.server;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.test;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 1bab620881..abc559459f 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
index cd8bde3a8e..067559f108 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs.server
Bundle-SymbolicName: org.eclipse.jgit.lfs.server
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Export-Package: org.eclipse.jgit.lfs.server;version="6.1.1";
+Export-Package: org.eclipse.jgit.lfs.server;version="6.2.0";
uses:="javax.servlet.http,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.fs;version="6.1.1";
+ org.eclipse.jgit.lfs.server.fs;version="6.2.0";
uses:="javax.servlet,
javax.servlet.http,
org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib",
- org.eclipse.jgit.lfs.server.internal;version="6.1.1";x-internal:=true,
- org.eclipse.jgit.lfs.server.s3;version="6.1.1";
+ org.eclipse.jgit.lfs.server.internal;version="6.2.0";x-internal:=true,
+ org.eclipse.jgit.lfs.server.s3;version="6.2.0";
uses:="org.eclipse.jgit.lfs.server,
org.eclipse.jgit.lfs.lib"
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -24,15 +24,15 @@ Import-Package: com.google.gson;version="[2.8.0,3.0.0)",
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.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.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 5a5b23add3..a640bf39ff 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.lfs.server - Sources
Bundle-SymbolicName: org.eclipse.jgit.lfs.server.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml
index ae27153d71..354ed59a79 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 e3c0af81de..19f852b72b 100644
--- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -3,27 +3,27 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs.test
Bundle-SymbolicName: org.eclipse.jgit.lfs.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
-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)",
+Import-Package: org.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.attributes;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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.1.1";x-friends:="org.eclipse.jgit.lfs.server.test"
+Export-Package: org.eclipse.jgit.lfs.test;version="6.2.0";x-friends:="org.eclipse.jgit.lfs.server.test"
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml
index 1d782e6fd3..5b401ad755 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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
index 98a0712e47..3ac41571a4 100644
--- 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
@@ -142,14 +142,6 @@ public class LfsConfigGitTest extends RepositoryTestCase {
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);
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
index 09ffffbf86..7a9b5b9e40 100644
--- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,33 +3,32 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.lfs
Bundle-SymbolicName: org.eclipse.jgit.lfs
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-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"
+Export-Package: org.eclipse.jgit.lfs;version="6.2.0",
+ org.eclipse.jgit.lfs.errors;version="6.2.0",
+ org.eclipse.jgit.lfs.internal;version="6.2.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server",
+ org.eclipse.jgit.lfs.lib;version="6.2.0"
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.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)"
+ org.eclipse.jgit.annotations;version="[6.2.0,6.3.0)";resolution:=optional,
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.attributes;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.diff;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.dircache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.hooks;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.pack;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.0,6.3.0)"
diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
index 7a2a446c48..2eef821118 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.lfs - Sources
Bundle-SymbolicName: org.eclipse.jgit.lfs.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml
index 949c568217..4d2766ee27 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 642b83db44..c4c0dacf42 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
@@ -6,14 +6,13 @@ incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH.
invalidLongId=Invalid id: {0}
invalidLongIdLength=Invalid id length {0}; should be {1}
lfsFailedToGetRepository=failed to get repository {0}
-lfsNoDownloadUrl="Need to download object from LFS server but couldn't determine LFS server URL"
+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"
+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}
-userConfigInvalid="User config file {0} invalid {1}"
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 ebf46e080e..9b3d60812a 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
@@ -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
@@ -101,8 +101,10 @@ public class LfsPrePushHook extends PrePushHook {
}
HttpConnection api = LfsConnectionFactory.getLfsConnection(
getRepository(), METHOD_POST, OPERATION_UPLOAD);
- Map<String, LfsPointer> oid2ptr = requestBatchUpload(api, toPush);
- uploadContents(api, oid2ptr);
+ if (!isDryRun()) {
+ Map<String, LfsPointer> oid2ptr = requestBatchUpload(api, toPush);
+ uploadContents(api, oid2ptr);
+ }
return EMPTY;
}
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
index 71d395ca84..857ccbe056 100644
--- 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
@@ -30,21 +30,26 @@ import org.eclipse.jgit.treewalk.TreeWalk;
import static org.eclipse.jgit.lib.Constants.HEAD;
/**
- * Encapsulate access to the .lfsconfig.
+ * Encapsulate access to the {@code .lfsconfig}.
+ * <p>
+ * According to the git lfs documentation the order to find the
+ * {@code .lfsconfig} file is:
+ * </p>
+ * <ol>
+ * <li>in the root of the working tree</li>
+ * <li>in the index</li>
+ * <li>in the HEAD; for bare repositories this is the only place that is
+ * searched</li>
+ * </ol>
+ * <p>
+ * Values from the {@code .lfsconfig} are used only if not specified in another
+ * git config file to allow local override without modifiction of a committed
+ * file.
+ * </p>
*
- * 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.
+ * @see <a href=
+ * "https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-config.5.ronn">Configuration
+ * options for git-lfs</a>
*/
public class LfsConfig {
private Repository db;
@@ -55,17 +60,30 @@ public class LfsConfig {
*
* @param db
* the associated repo
- * @throws IOException
*/
- public LfsConfig(Repository db) throws IOException {
+ public LfsConfig(Repository db) {
this.db = db;
- delegate = this.load();
+ }
+
+ /**
+ * Getter for the delegate to allow lazy initialization.
+ *
+ * @return the delegate {@link Config}
+ * @throws IOException
+ */
+ private Config getDelegate() throws IOException {
+ if (delegate == null) {
+ delegate = this.load();
+ }
+ return delegate;
}
/**
* Read the .lfsconfig file from the repository
*
- * @return The loaded lfs config or null if it does not exist
+ * An empty config is returned be empty if no lfs config exists.
+ *
+ * @return The loaded lfs config
*
* @throws IOException
*/
@@ -102,7 +120,7 @@ public class LfsConfig {
throws IOException {
File lfsConfig = db.getFS().resolve(db.getWorkTree(),
Constants.DOT_LFS_CONFIG);
- if (lfsConfig.exists() && lfsConfig.isFile()) {
+ if (lfsConfig.isFile()) {
FileBasedConfig config = new FileBasedConfig(lfsConfig, db.getFS());
try {
config.load();
@@ -188,12 +206,14 @@ public class LfsConfig {
* @param name
* the key name
* @return a String value from the config, <code>null</code> if not found
+ * @throws IOException
*/
+ @Nullable
public String getString(final String section, final String subsection,
- final String name) {
+ final String name) throws IOException {
String result = db.getConfig().getString(section, subsection, name);
if (result == null) {
- result = delegate.getString(section, subsection, name);
+ result = getDelegate().getString(section, subsection, name);
}
return result;
}
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 06234c1d90..8ef8f59f93 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
@@ -44,6 +44,5 @@ public class LfsText extends TranslationBundle {
/***/ public String repositoryReadOnly;
/***/ public String requiredHashFunctionNotAvailable;
/***/ public String serverFailure;
- /***/ public String userConfigInvalid;
/***/ public String wrongAmountOfDataReceived;
}
diff --git a/org.eclipse.jgit.packaging/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.packaging/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..99f26c0203
--- /dev/null
+++ b/org.eclipse.jgit.packaging/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
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 cd22e24ba8..2d52eeddef 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index 54feb9d384..7d591ed253 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..99f26c0203
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
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 2061948432..cd6746bb0f 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.2.0" 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 760903e7e0..17ead4e244 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index e899ad56d3..30812016fe 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.2.0" 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 b725dff216..cf091c30d8 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index 99073e4710..9d5839ebb6 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.1.1.qualifier"
+ version="6.2.0.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.1.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.2.0" 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 3566dbb4a0..938edc8ed5 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
index c04051b604..23159ecb6e 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.2.0" 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 50338a60c5..b416432880 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index 3939f51b9b..985233bfdb 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.1.1.qualifier"
+ version="6.2.0.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.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"/>
+ <import feature="org.eclipse.jgit" version="6.2.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit.lfs" version="6.2.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit.ssh.apache" version="6.2.0" match="equivalent"/>
</requires>
<plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 4b0e26aa94..bf8e938b89 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index 9ccf39eafa..b38d1135d3 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index d3e662b9ba..f64898d2c8 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.2.0" 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 d8b5de2436..fe364838db 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 e03964727e..503ce011a9 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import feature="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="6.2.0" 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 591b448016..ab1f5d37d3 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..99f26c0203
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
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 3df4a9284a..94485a285e 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.1.1.qualifier"
+ version="6.2.0.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -23,7 +23,7 @@
</url>
<requires>
- <import plugin="org.eclipse.jgit" version="6.1.1" match="equivalent"/>
+ <import plugin="org.eclipse.jgit" version="6.2.0" 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 e461bff45a..a93c70d69e 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..99f26c0203
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
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 5d61eefb64..a72e3851a2 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 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: JGit Target Platform Bundle
Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.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 4e4023232c..3d4f2378d1 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="1646256653">
+<target name="jgit-4.17" sequenceNumber="1654550635">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -27,8 +27,8 @@
<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"/>
- <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+ <unit id="com.jcraft.jzlib" version="1.1.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
<unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
@@ -39,8 +39,8 @@
<unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
- <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20210923-1401"/>
- <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20210923-1401"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
<unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
@@ -59,12 +59,12 @@
<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.70.0.v20220105-1522"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
<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.bcprov" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
<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"/>
@@ -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/R20220302172233/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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 dbb450a1dc..9c824c5fd4 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/R20220302172233-2022-03.tpd"
+include "orbit/R20220531185310-2022-06.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 1628217e04..603fefbadf 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="1646256653">
+<target name="jgit-4.18" sequenceNumber="1654550635">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -27,8 +27,8 @@
<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"/>
- <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+ <unit id="com.jcraft.jzlib" version="1.1.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
<unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
@@ -39,8 +39,8 @@
<unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
- <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20210923-1401"/>
- <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20210923-1401"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
<unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
@@ -59,12 +59,12 @@
<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.70.0.v20220105-1522"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
<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.bcprov" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
<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"/>
@@ -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/R20220302172233/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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 911c67c908..1dcdd9bebb 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/R20220302172233-2022-03.tpd"
+include "orbit/R20220531185310-2022-06.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 ab18f7b01c..cc418b1c8a 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="1646256653">
+<target name="jgit-4.19-staging" sequenceNumber="1654550632">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -27,8 +27,8 @@
<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"/>
- <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+ <unit id="com.jcraft.jzlib" version="1.1.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
<unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
@@ -39,8 +39,8 @@
<unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
- <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20210923-1401"/>
- <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20210923-1401"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
<unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
@@ -59,12 +59,12 @@
<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.70.0.v20220105-1522"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
<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.bcprov" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
<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"/>
@@ -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/R20220302172233/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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 fdb8b11f6f..806851c6e2 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/R20220302172233-2022-03.tpd"
+include "orbit/R20220531185310-2022-06.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 4c840dc34a..efcb591efa 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="1646256653">
+<target name="jgit-4.20" sequenceNumber="1654550634">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -27,8 +27,8 @@
<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"/>
- <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+ <unit id="com.jcraft.jzlib" version="1.1.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
<unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
@@ -39,8 +39,8 @@
<unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
- <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20210923-1401"/>
- <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20210923-1401"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
<unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
@@ -59,12 +59,12 @@
<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.70.0.v20220105-1522"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
<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.bcprov" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
<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"/>
@@ -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/R20220302172233/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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 120ee647b0..a3ea58300e 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/R20220302172233-2022-03.tpd"
+include "orbit/R20220531185310-2022-06.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 7e8cd91fe3..85ed31f441 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="1646256653">
+<target name="jgit-4.21" sequenceNumber="1654550635">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -27,8 +27,8 @@
<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"/>
- <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+ <unit id="com.jcraft.jzlib" version="1.1.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
<unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
@@ -39,8 +39,8 @@
<unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
- <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20210923-1401"/>
- <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20210923-1401"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
<unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
@@ -59,12 +59,12 @@
<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.70.0.v20220105-1522"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
<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.bcprov" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
<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"/>
@@ -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/R20220302172233/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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 0ec2a52a2c..0808601826 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/R20220302172233-2022-03.tpd"
+include "orbit/R20220531185310-2022-06.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 b229da160b..e7b5a31992 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="1646256653">
+<target name="jgit-4.22" sequenceNumber="1654550634">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="jakarta.servlet-api" version="4.0.0"/>
@@ -27,8 +27,8 @@
<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"/>
- <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/>
+ <unit id="com.jcraft.jzlib" version="1.1.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
<unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
<unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
@@ -39,8 +39,8 @@
<unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
- <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20210923-1401"/>
- <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20210923-1401"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
<unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
<unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
@@ -59,12 +59,12 @@
<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.70.0.v20220105-1522"/>
- <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220105-1522"/>
+ <unit id="org.bouncycastle.bcpg" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
<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.bcprov" version="1.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
<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"/>
@@ -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/R20220302172233/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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 eb1723c736..5697574d3f 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/R20220302172233-2022-03.tpd"
+include "orbit/R20220531185310-2022-06.tpd"
location "https://download.eclipse.org/releases/2021-12/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target
new file mode 100644
index 0000000000..3c18e4b75c
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
+<target name="jgit-4.23" sequenceNumber="1654550634">
+ <locations>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="jakarta.servlet-api" version="4.0.0"/>
+ <unit id="jakarta.servlet-api.source" version="4.0.0"/>
+ <unit id="org.eclipse.jetty.http" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.http.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.io" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.io.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.security" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.security.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.server" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.server.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.servlet" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util.ajax" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util.ajax.source" version="10.0.6"/>
+ <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.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.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
+ <unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
+ <unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
+ <unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
+ <unit id="com.sun.jna.platform.source" version="5.8.0.v20210406-1004"/>
+ <unit id="javaewah" version="1.1.13.v20211029-0839"/>
+ <unit id="javaewah.source" version="1.1.13.v20211029-0839"/>
+ <unit id="net.bytebuddy.byte-buddy" version="1.9.0.v20181107-1410"/>
+ <unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
+ <unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
+ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
+ <unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
+ <unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
+ <unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
+ <unit id="org.apache.commons.codec.source" version="1.14.0.v20200818-1422"/>
+ <unit id="org.apache.commons.compress" version="1.21.0.v20211103-2100"/>
+ <unit id="org.apache.commons.compress.source" version="1.21.0.v20211103-2100"/>
+ <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
+ <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.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.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
+ <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.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
+ <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"/>
+ <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+ <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+ <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
+ <unit id="org.junit" version="4.13.2.v20211018-1956"/>
+ <unit id="org.junit.source" version="4.13.2.v20211018-1956"/>
+ <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
+ <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
+ <unit id="org.mockito" version="2.23.0.v20200310-1642"/>
+ <unit id="org.mockito.source" version="2.23.0.v20200310-1642"/>
+ <unit id="org.objenesis" version="2.6.0.v20180420-1519"/>
+ <unit id="org.objenesis.source" version="2.6.0.v20180420-1519"/>
+ <unit id="org.slf4j.api" version="1.7.30.v20200204-2150"/>
+ <unit id="org.slf4j.api.source" version="1.7.30.v20200204-2150"/>
+ <unit id="org.slf4j.binding.simple" version="1.7.30.v20200204-2150"/>
+ <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/R20220531185310/repository"/>
+ </location>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="org.eclipse.osgi" version="0.0.0"/>
+ <repository location="https://download.eclipse.org/releases/2022-03/"/>
+ </location>
+ </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd
new file mode 100644
index 0000000000..7fd421a882
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.23" with source configurePhase
+
+include "projects/jetty-10.0.x.tpd"
+include "orbit/R20220531185310-2022-06.tpd"
+
+location "https://download.eclipse.org/releases/2022-03/" {
+ org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target
new file mode 100644
index 0000000000..b622b4e91e
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
+<target name="jgit-4.24" sequenceNumber="1654550621">
+ <locations>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="jakarta.servlet-api" version="4.0.0"/>
+ <unit id="jakarta.servlet-api.source" version="4.0.0"/>
+ <unit id="org.eclipse.jetty.http" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.http.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.io" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.io.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.security" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.security.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.server" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.server.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.servlet" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util.source" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util.ajax" version="10.0.6"/>
+ <unit id="org.eclipse.jetty.util.ajax.source" version="10.0.6"/>
+ <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.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.3.v20220502-1820"/>
+ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20220502-1820"/>
+ <unit id="com.sun.jna" version="5.8.0.v20210503-0343"/>
+ <unit id="com.sun.jna.source" version="5.8.0.v20210503-0343"/>
+ <unit id="com.sun.jna.platform" version="5.8.0.v20210406-1004"/>
+ <unit id="com.sun.jna.platform.source" version="5.8.0.v20210406-1004"/>
+ <unit id="javaewah" version="1.1.13.v20211029-0839"/>
+ <unit id="javaewah.source" version="1.1.13.v20211029-0839"/>
+ <unit id="net.bytebuddy.byte-buddy" version="1.9.0.v20181107-1410"/>
+ <unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/>
+ <unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/>
+ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
+ <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20220506-1020"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20220506-1020"/>
+ <unit id="org.apache.ant" version="1.10.12.v20211102-1452"/>
+ <unit id="org.apache.ant.source" version="1.10.12.v20211102-1452"/>
+ <unit id="org.apache.commons.codec" version="1.14.0.v20200818-1422"/>
+ <unit id="org.apache.commons.codec.source" version="1.14.0.v20200818-1422"/>
+ <unit id="org.apache.commons.compress" version="1.21.0.v20211103-2100"/>
+ <unit id="org.apache.commons.compress.source" version="1.21.0.v20211103-2100"/>
+ <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/>
+ <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.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.70.0.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.70.0.v20220507-1208"/>
+ <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.v20220507-1208"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.70.0.v20220507-1208"/>
+ <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"/>
+ <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/>
+ <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/>
+ <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/>
+ <unit id="org.junit" version="4.13.2.v20211018-1956"/>
+ <unit id="org.junit.source" version="4.13.2.v20211018-1956"/>
+ <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/>
+ <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/>
+ <unit id="org.mockito" version="2.23.0.v20200310-1642"/>
+ <unit id="org.mockito.source" version="2.23.0.v20200310-1642"/>
+ <unit id="org.objenesis" version="2.6.0.v20180420-1519"/>
+ <unit id="org.objenesis.source" version="2.6.0.v20180420-1519"/>
+ <unit id="org.slf4j.api" version="1.7.30.v20200204-2150"/>
+ <unit id="org.slf4j.api.source" version="1.7.30.v20200204-2150"/>
+ <unit id="org.slf4j.binding.simple" version="1.7.30.v20200204-2150"/>
+ <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/R20220531185310/repository"/>
+ </location>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="org.eclipse.osgi" version="0.0.0"/>
+ <repository location="https://download.eclipse.org/staging/2022-06/"/>
+ </location>
+ </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd
new file mode 100644
index 0000000000..e81eec9eb6
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.24" with source configurePhase
+
+include "projects/jetty-10.0.x.tpd"
+include "orbit/R20220531185310-2022-06.tpd"
+
+location "https://download.eclipse.org/staging/2022-06/" {
+ org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd
new file mode 100644
index 0000000000..3c74497c21
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd
@@ -0,0 +1,69 @@
+target "R20220531185310-2022-06" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/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.3.v20220502-1820,1.1.3.v20220502-1820]
+ com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820]
+ 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.v20220506-1020,0.3.0.v20220506-1020]
+ net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020]
+ 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.v20220507-1208,1.70.0.v20220507-1208]
+ org.bouncycastle.bcpg.source [1.70.0.v20220507-1208,1.70.0.v20220507-1208]
+ 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.v20220507-1208,1.70.0.v20220507-1208]
+ org.bouncycastle.bcprov.source [1.70.0.v20220507-1208,1.70.0.v20220507-1208]
+ 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 2a95042eed..2296e95ed8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -16,37 +16,10 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.target</artifactId>
<packaging>pom</packaging>
<name>JGit Target Platform</name>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-artifacts</id>
- <phase>package</phase>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <configuration>
- <artifacts>
- <artifact>
- <file>${target-platform}.target</file>
- <type>target</type>
- <classifier>${target-platform}</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
</project> \ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index b6505980e5..bfcfd65c21 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -16,14 +16,14 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JGit Tycho Parent</name>
<properties>
<java.version>11</java.version>
- <tycho-version>2.5.0</tycho-version>
+ <tycho-version>2.6.0</tycho-version>
<tycho-extras-version>${tycho-version}</tycho-extras-version>
<target-platform>jgit-4.17</target-platform>
</properties>
@@ -231,12 +231,7 @@
<resolver>p2</resolver>
<pomDependencies>consider</pomDependencies>
<target>
- <artifact>
- <groupId>org.eclipse.jgit</groupId>
- <artifactId>org.eclipse.jgit.target</artifactId>
- <version>${project.version}</version>
- <classifier>${target-platform}</classifier>
- </artifact>
+ <file>${project.basedir}/../org.eclipse.jgit.target/${target-platform}.target</file>
</target>
<environments>
<environment>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index f5c4de477c..c1b6ae6422 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -3,31 +3,31 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.pgm.test
Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11
-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)",
+Import-Package: org.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.diff;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.dircache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="6.2.0",
+ org.eclipse.jgit.internal.storage.file;version="6.2.0",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.merge;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.pgm;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.pgm.opt;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.0,6.3.0)",
+ org.hamcrest.core;bundle-version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.rules;version="[4.13,5.0.0)",
org.kohsuke.args4j;version="[2.33.0,3.0.0)"
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index c824788255..d26919a4d6 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
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
index e7bf48417d..2b50d45253 100644
--- 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
+ * Copyright (C) 2021-2022, 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
@@ -9,72 +9,145 @@
*/
package org.eclipse.jgit.pgm;
-import static org.junit.Assert.assertEquals;
+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_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
+import static org.junit.Assert.fail;
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
-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.eclipse.jgit.internal.diffmergetool.DiffTools;
+import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
+import org.eclipse.jgit.lib.StoredConfig;
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;
+public class DiffToolTest extends ToolTestCase {
- @Argument(index = 1, metaVar = "metaVar_arg")
- List<String> arguments = new ArrayList<>();
- }
+ private static final String DIFF_TOOL = CONFIG_DIFFTOOL_SECTION;
- private String[] runAndCaptureUsingInitRaw(String... args)
- throws Exception {
- CLIGitCommand.Result result = new CLIGitCommand.Result();
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ configureEchoTool(TOOL_NAME);
+ }
- GitCliJGitWrapperParser bean = new GitCliJGitWrapperParser();
- CmdLineParser clp = new CmdLineParser(bean);
- clp.parseArgument(args);
+ @Test(expected = Die.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ String[] conflictingFilenames = createUnstagedChanges();
- 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();
+ List<String> expectedErrors = new ArrayList<>();
+ for (String changedFilename : conflictingFilenames) {
+ expectedErrors.add("External diff tool is not defined: " + toolName);
+ expectedErrors.add("compare of " + changedFilename + " failed");
}
- if (cmd.getErrorWriter() != null) {
- cmd.getErrorWriter().flush();
- }
- return result.outLines().toArray(new String[0]);
+
+ runAndCaptureUsingInitRaw(expectedErrors, DIFF_TOOL, "--no-prompt",
+ "--tool", toolName);
+ fail("Expected exception to be thrown due to undefined external tool");
}
- private Git git;
+ @Test(expected = Die.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- git = new Git(db);
- git.commit().setMessage("initial commit").call();
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ StoredConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ createMergeConflict();
+ runAndCaptureUsingInitRaw(DIFF_TOOL, "--no-prompt", "--tool", toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = Die.class)
+ public void testEmptyToolName() throws Exception {
+ String emptyToolName = "";
+
+ StoredConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ emptyToolName);
+
+ createUnstagedChanges();
+
+ String araxisErrorLine = "compare: unrecognized option `-wait' @ error/compare.c/CompareImageCommand/1123.";
+ String[] expectedErrorOutput = { araxisErrorLine, araxisErrorLine, };
+ runAndCaptureUsingInitRaw(Arrays.asList(expectedErrorOutput), DIFF_TOOL,
+ "--no-prompt");
+ fail("Expected exception to be thrown due to external tool exiting with an error");
+ }
+
+ @Test
+ public void testToolWithPrompt() throws Exception {
+ String[] inputLines = {
+ "y", // accept launching diff tool
+ "y", // accept launching diff tool
+ };
+
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedCompareOutput(conflictingFilenames);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(inputStream,
+ DIFF_TOOL, "--prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testToolAbortLaunch() throws Exception {
+ String[] inputLines = {
+ "y", // accept launching diff tool
+ "n", // don't launch diff tool
+ };
+
+ String[] conflictingFilenames = createUnstagedChanges();
+ int abortIndex = 1;
+ String[] expectedOutput = getExpectedAbortOutput(conflictingFilenames, abortIndex);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput,
+ runAndCaptureUsingInitRaw(inputStream, DIFF_TOOL, "--prompt", option,
+ TOOL_NAME));
+ }
+
+ @Test(expected = Die.class)
+ public void testNotDefinedTool() throws Exception {
+ createUnstagedChanges();
+
+ runAndCaptureUsingInitRaw(DIFF_TOOL, "--tool", "undefined");
+ fail("Expected exception when trying to run undefined tool");
}
@Test
public void testTool() throws Exception {
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedDiffToolOutput(changes);
+ String[] conflictFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictFilenames);
String[] options = {
"--tool",
@@ -84,69 +157,88 @@ public class DiffToolTest extends CLIRepositoryTestCase {
for (String option : options) {
assertArrayOfLinesEquals("Incorrect output for option: " + option,
expectedOutput,
- runAndCaptureUsingInitRaw("difftool", option,
- "some_tool"));
+ runAndCaptureUsingInitRaw(DIFF_TOOL, option,
+ TOOL_NAME));
}
}
@Test
public void testToolTrustExitCode() throws Exception {
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedDiffToolOutput(changes);
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
String[] options = { "--tool", "-t", };
for (String option : options) {
assertArrayOfLinesEquals("Incorrect output for option: " + option,
- expectedOutput, runAndCaptureUsingInitRaw("difftool",
- "--trust-exit-code", option, "some_tool"));
+ expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL,
+ "--trust-exit-code", option, TOOL_NAME));
}
}
@Test
public void testToolNoGuiNoPromptNoTrustExitcode() throws Exception {
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedDiffToolOutput(changes);
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
String[] options = { "--tool", "-t", };
for (String option : options) {
assertArrayOfLinesEquals("Incorrect output for option: " + option,
- expectedOutput, runAndCaptureUsingInitRaw("difftool",
+ expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL,
"--no-gui", "--no-prompt", "--no-trust-exit-code",
- option, "some_tool"));
+ option, TOOL_NAME));
}
}
@Test
public void testToolCached() throws Exception {
- RevCommit commit = createStagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedDiffToolOutput(changes);
+ String[] conflictingFilenames = createStagedChanges();
+ Pattern[] expectedOutput = getExpectedCachedToolOutputNoPrompt(conflictingFilenames);
String[] options = { "--cached", "--staged", };
for (String option : options) {
- assertArrayOfLinesEquals("Incorrect output for option: " + option,
- expectedOutput, runAndCaptureUsingInitRaw("difftool",
- option, "--tool", "some_tool"));
+ assertArrayOfMatchingLines("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL,
+ option, "--tool", TOOL_NAME));
}
}
@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();
+
+ DiffTools diffTools = new DiffTools(db);
+ Map<String, ExternalDiffTool> predefinedTools = diffTools
+ .getPredefinedTools(true);
+ List<ExternalDiffTool> availableTools = new ArrayList<>();
+ List<ExternalDiffTool> notAvailableTools = new ArrayList<>();
+ for (ExternalDiffTool tool : predefinedTools.values()) {
+ if (tool.isAvailable()) {
+ availableTools.add(tool);
+ } else {
+ notAvailableTools.add(tool);
+ }
+ }
+
+ expectedOutput.add(
+ "'git difftool --tool=<tool>' may be set to one of the following:");
+ for (ExternalDiffTool tool : availableTools) {
+ String toolName = tool.getName();
+ expectedOutput.add(toolName);
+ }
+ String customToolHelpLine = TOOL_NAME + "." + CONFIG_KEY_CMD + " "
+ + getEchoCommand();
+ expectedOutput.add("user-defined:");
+ expectedOutput.add(customToolHelpLine);
+ expectedOutput.add(
+ "The following tools are valid, but not currently available:");
+ for (ExternalDiffTool tool : notAvailableTools) {
+ String toolName = tool.getName();
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.",
};
@@ -154,52 +246,99 @@ public class DiffToolTest extends CLIRepositoryTestCase {
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;
+ expectedOutput.toArray(new String[0]),
+ runAndCaptureUsingInitRaw(DIFF_TOOL, option));
+ }
+
+ private void configureEchoTool(String toolName) {
+ StoredConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ String command = getEchoCommand();
+
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ /*
+ * prevent prompts as we are running in tests and there is no user to
+ * interact with on the command line
+ */
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_PROMPT,
+ String.valueOf(false));
+ }
+
+ private String[] getExpectedToolOutputNoPrompt(String[] conflictingFilenames) {
+ String[] expectedToolOutput = new String[conflictingFilenames.length];
+ for (int i = 0; i < conflictingFilenames.length; ++i) {
+ String newPath = conflictingFilenames[i];
+ Path fullPath = getFullPath(newPath);
+ expectedToolOutput[i] = fullPath.toString();
}
return expectedToolOutput;
}
- private static void assertArrayOfLinesEquals(String failMessage,
- String[] expected, String[] actual) {
- assertEquals(failMessage, toString(expected), toString(actual));
+ private Pattern[] getExpectedCachedToolOutputNoPrompt(String[] conflictingFilenames) {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir.endsWith(File.separator)) {
+ tmpDir = tmpDir.substring(0, tmpDir.length() - 1);
+ }
+ Pattern emptyPattern = Pattern.compile("");
+ List<Pattern> expectedToolOutput = new ArrayList<>();
+ for (int i = 0; i < conflictingFilenames.length; ++i) {
+ String changedFilename = conflictingFilenames[i];
+ Path fullPath = getFullPath(changedFilename);
+ String filename = fullPath.getFileName().toString();
+ String regexp = tmpDir + File.separatorChar + filename
+ + "_REMOTE_.*";
+ Pattern pattern = Pattern.compile(regexp);
+ expectedToolOutput.add(pattern);
+ expectedToolOutput.add(emptyPattern);
+ }
+ expectedToolOutput.add(emptyPattern);
+ return expectedToolOutput.toArray(new Pattern[0]);
+ }
+
+ private String[] getExpectedCompareOutput(String[] conflictingFilenames) {
+ List<String> expected = new ArrayList<>();
+ int n = conflictingFilenames.length;
+ for (int i = 0; i < n; ++i) {
+ String changedFilename = conflictingFilenames[i];
+ expected.add(
+ "Viewing (" + (i + 1) + "/" + n + "): '" + changedFilename
+ + "'");
+ expected.add("Launch '" + TOOL_NAME + "' [Y/n]?");
+ Path fullPath = getFullPath(changedFilename);
+ expected.add(fullPath.toString());
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private String[] getExpectedAbortOutput(String[] conflictingFilenames,
+ int abortIndex) {
+ List<String> expected = new ArrayList<>();
+ int n = conflictingFilenames.length;
+ for (int i = 0; i < n; ++i) {
+ String changedFilename = conflictingFilenames[i];
+ expected.add(
+ "Viewing (" + (i + 1) + "/" + n + "): '" + changedFilename
+ + "'");
+ expected.add("Launch '" + TOOL_NAME + "' [Y/n]?");
+ if (i == abortIndex) {
+ break;
+ }
+ Path fullPath = getFullPath(changedFilename);
+ expected.add(fullPath.toString());
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private static String getEchoCommand() {
+ /*
+ * use 'REMOTE' placeholder, as it will be replaced by a file path
+ * within the repository.
+ */
+ return "(echo \"$REMOTE\")";
}
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java
new file mode 100644
index 0000000000..1236dd30d3
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2022, 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.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
+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_MERGETOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION;
+import static org.junit.Assert.fail;
+
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.internal.diffmergetool.ExternalMergeTool;
+import org.eclipse.jgit.internal.diffmergetool.MergeTools;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Testing the {@code mergetool} command.
+ */
+public class MergeToolTest extends ToolTestCase {
+
+ private static final String MERGE_TOOL = CONFIG_MERGETOOL_SECTION;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ configureEchoTool(TOOL_NAME);
+ }
+
+ @Test
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ String[] conflictingFilenames = createMergeConflict();
+
+ List<String> expectedErrors = new ArrayList<>();
+ for (String conflictingFilename : conflictingFilenames) {
+ expectedErrors.add("External merge tool is not defined: " + toolName);
+ expectedErrors.add("merge of " + conflictingFilename + " failed");
+ }
+
+ runAndCaptureUsingInitRaw(expectedErrors, MERGE_TOOL,
+ "--no-prompt", "--tool", toolName);
+ }
+
+ @Test(expected = Die.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ StoredConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ createMergeConflict();
+ runAndCaptureUsingInitRaw(MERGE_TOOL, "--no-prompt", "--tool",
+ toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test
+ public void testEmptyToolName() throws Exception {
+ String emptyToolName = "";
+
+ StoredConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ emptyToolName);
+
+ createMergeConflict();
+
+ String araxisErrorLine = "compare: unrecognized option `-wait' @ error/compare.c/CompareImageCommand/1123.";
+ String[] expectedErrorOutput = { araxisErrorLine, araxisErrorLine, };
+ runAndCaptureUsingInitRaw(Arrays.asList(expectedErrorOutput),
+ MERGE_TOOL, "--no-prompt");
+ }
+
+ @Test
+ public void testAbortMerge() throws Exception {
+ String[] inputLines = {
+ "y", // start tool for merge resolution
+ "n", // don't accept merge tool result
+ "n", // don't continue resolution
+ };
+ String[] conflictingFilenames = createMergeConflict();
+ int abortIndex = 1;
+ String[] expectedOutput = getExpectedAbortMergeOutput(
+ conflictingFilenames,
+ abortIndex);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(inputStream,
+ MERGE_TOOL, "--prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testAbortLaunch() throws Exception {
+ String[] inputLines = {
+ "n", // abort merge tool launch
+ };
+ String[] conflictingFilenames = createMergeConflict();
+ String[] expectedOutput = getExpectedAbortLaunchOutput(
+ conflictingFilenames);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(inputStream,
+ MERGE_TOOL, "--prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testMergeConflict() throws Exception {
+ String[] inputLines = {
+ "y", // start tool for merge resolution
+ "y", // accept merge result as successful
+ "y", // start tool for merge resolution
+ "y", // accept merge result as successful
+ };
+ String[] conflictingFilenames = createMergeConflict();
+ String[] expectedOutput = getExpectedMergeConflictOutput(
+ conflictingFilenames);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(inputStream,
+ MERGE_TOOL, "--prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testDeletedConflict() throws Exception {
+ String[] inputLines = {
+ "d", // choose delete option to resolve conflict
+ "m", // choose merge option to resolve conflict
+ };
+ String[] conflictingFilenames = createDeletedConflict();
+ String[] expectedOutput = getExpectedDeletedConflictOutput(
+ conflictingFilenames);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(inputStream,
+ MERGE_TOOL, "--prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testNoConflict() throws Exception {
+ createStagedChanges();
+ String[] expectedOutput = { "No files need merging" };
+
+ String[] options = { "--tool", "-t", };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput,
+ runAndCaptureUsingInitRaw(MERGE_TOOL, option, TOOL_NAME));
+ }
+ }
+
+ @Test
+ public void testMergeConflictNoPrompt() throws Exception {
+ String[] conflictingFilenames = createMergeConflict();
+ String[] expectedOutput = getExpectedMergeConflictOutputNoPrompt(
+ conflictingFilenames);
+
+ String option = "--tool";
+
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput,
+ runAndCaptureUsingInitRaw(MERGE_TOOL, option, TOOL_NAME));
+ }
+
+ @Test
+ public void testMergeConflictNoGuiNoPrompt() throws Exception {
+ String[] conflictingFilenames = createMergeConflict();
+ String[] expectedOutput = getExpectedMergeConflictOutputNoPrompt(
+ conflictingFilenames);
+
+ String option = "--tool";
+
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(MERGE_TOOL,
+ "--no-gui", "--no-prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testToolHelp() throws Exception {
+ List<String> expectedOutput = new ArrayList<>();
+
+ MergeTools diffTools = new MergeTools(db);
+ Map<String, ExternalMergeTool> predefinedTools = diffTools
+ .getPredefinedTools(true);
+ List<ExternalMergeTool> availableTools = new ArrayList<>();
+ List<ExternalMergeTool> notAvailableTools = new ArrayList<>();
+ for (ExternalMergeTool tool : predefinedTools.values()) {
+ if (tool.isAvailable()) {
+ availableTools.add(tool);
+ } else {
+ notAvailableTools.add(tool);
+ }
+ }
+
+ expectedOutput.add(
+ "'git mergetool --tool=<tool>' may be set to one of the following:");
+ for (ExternalMergeTool tool : availableTools) {
+ String toolName = tool.getName();
+ expectedOutput.add(toolName);
+ }
+ String customToolHelpLine = TOOL_NAME + "." + CONFIG_KEY_CMD + " "
+ + getEchoCommand();
+ expectedOutput.add("user-defined:");
+ expectedOutput.add(customToolHelpLine);
+ expectedOutput.add(
+ "The following tools are valid, but not currently available:");
+ for (ExternalMergeTool tool : notAvailableTools) {
+ String toolName = tool.getName();
+ expectedOutput.add(toolName);
+ }
+ String[] userDefinedToolsHelp = {
+ "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(MERGE_TOOL, option));
+ }
+
+ private void configureEchoTool(String toolName) {
+ StoredConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ String command = getEchoCommand();
+
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ /*
+ * prevent prompts as we are running in tests and there is no user to
+ * interact with on the command line
+ */
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_PROMPT,
+ String.valueOf(false));
+ }
+
+ private String[] getExpectedMergeConflictOutputNoPrompt(
+ String[] conflictFilenames) {
+ List<String> expected = new ArrayList<>();
+ expected.add("Merging:");
+ for (String conflictFilename : conflictFilenames) {
+ expected.add(conflictFilename);
+ }
+ for (String conflictFilename : conflictFilenames) {
+ expected.add("Normal merge conflict for '" + conflictFilename
+ + "':");
+ expected.add("{local}: modified file");
+ expected.add("{remote}: modified file");
+ Path filePath = getFullPath(conflictFilename);
+ expected.add(filePath.toString());
+ expected.add(conflictFilename + " seems unchanged.");
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private static String[] getExpectedAbortLaunchOutput(
+ String[] conflictFilenames) {
+ List<String> expected = new ArrayList<>();
+ expected.add("Merging:");
+ for (String conflictFilename : conflictFilenames) {
+ expected.add(conflictFilename);
+ }
+ if (conflictFilenames.length > 1) {
+ String conflictFilename = conflictFilenames[0];
+ expected.add(
+ "Normal merge conflict for '" + conflictFilename + "':");
+ expected.add("{local}: modified file");
+ expected.add("{remote}: modified file");
+ expected.add("Hit return to start merge resolution tool ("
+ + TOOL_NAME + "):");
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private String[] getExpectedAbortMergeOutput(
+ String[] conflictFilenames, int abortIndex) {
+ List<String> expected = new ArrayList<>();
+ expected.add("Merging:");
+ for (String conflictFilename : conflictFilenames) {
+ expected.add(conflictFilename);
+ }
+ for (int i = 0; i < conflictFilenames.length; ++i) {
+ if (i == abortIndex) {
+ break;
+ }
+
+ String conflictFilename = conflictFilenames[i];
+ expected.add(
+ "Normal merge conflict for '" + conflictFilename + "':");
+ expected.add("{local}: modified file");
+ expected.add("{remote}: modified file");
+ Path fullPath = getFullPath(conflictFilename);
+ expected.add("Hit return to start merge resolution tool ("
+ + TOOL_NAME + "): " + fullPath);
+ expected.add(conflictFilename + " seems unchanged.");
+ expected.add("Was the merge successful [y/n]?");
+ if (i < conflictFilenames.length - 1) {
+ expected.add(
+ "\tContinue merging other unresolved paths [y/n]?");
+ }
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private String[] getExpectedMergeConflictOutput(
+ String[] conflictFilenames) {
+ List<String> expected = new ArrayList<>();
+ expected.add("Merging:");
+ for (String conflictFilename : conflictFilenames) {
+ expected.add(conflictFilename);
+ }
+ for (int i = 0; i < conflictFilenames.length; ++i) {
+ String conflictFilename = conflictFilenames[i];
+ expected.add("Normal merge conflict for '" + conflictFilename
+ + "':");
+ expected.add("{local}: modified file");
+ expected.add("{remote}: modified file");
+ Path filePath = getFullPath(conflictFilename);
+ expected.add("Hit return to start merge resolution tool ("
+ + TOOL_NAME + "): " + filePath);
+ expected.add(conflictFilename + " seems unchanged.");
+ expected.add("Was the merge successful [y/n]?");
+ if (i < conflictFilenames.length - 1) {
+ // expected.add(
+ // "\tContinue merging other unresolved paths [y/n]?");
+ }
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private static String[] getExpectedDeletedConflictOutput(
+ String[] conflictFilenames) {
+ List<String> expected = new ArrayList<>();
+ expected.add("Merging:");
+ for (String mergeConflictFilename : conflictFilenames) {
+ expected.add(mergeConflictFilename);
+ }
+ for (int i = 0; i < conflictFilenames.length; ++i) {
+ String conflictFilename = conflictFilenames[i];
+ expected.add(conflictFilename + " seems unchanged.");
+ expected.add("{local}: deleted");
+ expected.add("{remote}: modified file");
+ expected.add("Use (m)odified or (d)eleted file, or (a)bort?");
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private static String getEchoCommand() {
+ /*
+ * use 'MERGED' placeholder, as both 'LOCAL' and 'REMOTE' will be
+ * replaced with full paths to a temporary file during some of the tests
+ */
+ return "(echo \"$MERGED\")";
+ }
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java
new file mode 100644
index 0000000000..a3c41f0fed
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022, 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 static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.diff.DiffEntry;
+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.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+
+/**
+ * Base test case for the {@code difftool} and {@code mergetool} commands.
+ */
+public abstract class ToolTestCase 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<>();
+ }
+
+ protected static final String TOOL_NAME = "some_tool";
+
+ private static final String TEST_BRANCH_NAME = "test_branch";
+
+ private Git git;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+ git.commit().setMessage("initial commit").call();
+ git.branchCreate().setName(TEST_BRANCH_NAME).call();
+ }
+
+ protected String[] runAndCaptureUsingInitRaw(String... args)
+ throws Exception {
+ InputStream inputStream = null; // no input stream
+ return runAndCaptureUsingInitRaw(inputStream, args);
+ }
+
+ protected String[] runAndCaptureUsingInitRaw(
+ List<String> expectedErrorOutput, String... args) throws Exception {
+ InputStream inputStream = null; // no input stream
+ return runAndCaptureUsingInitRaw(inputStream, expectedErrorOutput,
+ args);
+ }
+
+ protected String[] runAndCaptureUsingInitRaw(InputStream inputStream,
+ String... args) throws Exception {
+ List<String> expectedErrorOutput = Collections.emptyList();
+ return runAndCaptureUsingInitRaw(inputStream, expectedErrorOutput,
+ args);
+ }
+
+ protected String[] runAndCaptureUsingInitRaw(InputStream inputStream,
+ List<String> expectedErrorOutput, String... args)
+ throws CmdLineException, Exception, IOException {
+ 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, inputStream, 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();
+ }
+
+ List<String> errLines = result.errLines().stream()
+ .filter(l -> !l.isBlank()) // we care only about error messages
+ .collect(Collectors.toList());
+ assertEquals("Expected no standard error output from tool",
+ expectedErrorOutput.toString(), errLines.toString());
+
+ return result.outLines().toArray(new String[0]);
+ }
+
+ protected String[] createMergeConflict() throws Exception {
+ // create files on initial branch
+ git.checkout().setName(TEST_BRANCH_NAME).call();
+ writeTrashFile("dir1/a", "Hello world a");
+ writeTrashFile("dir2/b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("files a & b added").call();
+ // create another branch and change files
+ git.branchCreate().setName("branch_1").call();
+ git.checkout().setName("branch_1").call();
+ writeTrashFile("dir1/a", "Hello world a 1");
+ writeTrashFile("dir2/b", "Hello world b 1");
+ git.add().addFilepattern(".").call();
+ RevCommit commit1 = git.commit()
+ .setMessage("files a & b modified commit 1").call();
+ // checkout initial branch
+ git.checkout().setName(TEST_BRANCH_NAME).call();
+ // create another branch and change files
+ git.branchCreate().setName("branch_2").call();
+ git.checkout().setName("branch_2").call();
+ writeTrashFile("dir1/a", "Hello world a 2");
+ writeTrashFile("dir2/b", "Hello world b 2");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("files a & b modified commit 2").call();
+ // cherry-pick conflicting changes
+ git.cherryPick().include(commit1).call();
+ String[] conflictingFilenames = { "dir1/a", "dir2/b" };
+ return conflictingFilenames;
+ }
+
+ protected String[] createDeletedConflict() throws Exception {
+ // create files on initial branch
+ git.checkout().setName(TEST_BRANCH_NAME).call();
+ writeTrashFile("dir1/a", "Hello world a");
+ writeTrashFile("dir2/b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("files a & b added").call();
+ // create another branch and change files
+ git.branchCreate().setName("branch_1").call();
+ git.checkout().setName("branch_1").call();
+ writeTrashFile("dir1/a", "Hello world a 1");
+ writeTrashFile("dir2/b", "Hello world b 1");
+ git.add().addFilepattern(".").call();
+ RevCommit commit1 = git.commit()
+ .setMessage("files a & b modified commit 1").call();
+ // checkout initial branch
+ git.checkout().setName(TEST_BRANCH_NAME).call();
+ // create another branch and change files
+ git.branchCreate().setName("branch_2").call();
+ git.checkout().setName("branch_2").call();
+ git.rm().addFilepattern("dir1/a").call();
+ git.rm().addFilepattern("dir2/b").call();
+ git.commit().setMessage("files a & b deleted commit 2").call();
+ // cherry-pick conflicting changes
+ git.cherryPick().include(commit1).call();
+ String[] conflictingFilenames = { "dir1/a", "dir2/b" };
+ return conflictingFilenames;
+ }
+
+ protected String[] createUnstagedChanges() throws Exception {
+ writeTrashFile("dir1/a", "Hello world a");
+ writeTrashFile("dir2/b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("files a & b").call();
+ writeTrashFile("dir1/a", "New Hello world a");
+ writeTrashFile("dir2/b", "New Hello world b");
+ String[] conflictingFilenames = { "dir1/a", "dir2/b" };
+ return conflictingFilenames;
+ }
+
+ protected String[] createStagedChanges() throws Exception {
+ String[] conflictingFilenames = createUnstagedChanges();
+ git.add().addFilepattern(".").call();
+ return conflictingFilenames;
+ }
+
+ protected 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;
+ }
+
+ protected Path getFullPath(String repositoryFilename) {
+ Path dotGitPath = db.getDirectory().toPath();
+ Path repositoryRoot = dotGitPath.getParent();
+ Path repositoryFilePath = repositoryRoot.resolve(repositoryFilename);
+ return repositoryFilePath;
+ }
+
+ protected static InputStream createInputStream(String[] inputLines) {
+ return createInputStream(Arrays.asList(inputLines));
+ }
+
+ protected static InputStream createInputStream(List<String> inputLines) {
+ String input = String.join(System.lineSeparator(), inputLines);
+ InputStream inputStream = new ByteArrayInputStream(input.getBytes());
+ return inputStream;
+ }
+
+ protected static void assertArrayOfLinesEquals(String failMessage,
+ String[] expected, String[] actual) {
+ assertEquals(failMessage, toString(expected), toString(actual));
+ }
+
+ protected static void assertArrayOfMatchingLines(String failMessage,
+ Pattern[] expected, String[] actual) {
+ assertEquals(failMessage + System.lineSeparator()
+ + "Expected and actual lines count don't match. Expected: "
+ + Arrays.asList(expected) + ", actual: "
+ + Arrays.asList(actual), expected.length, actual.length);
+ int n = expected.length;
+ for (int i = 0; i < n; ++i) {
+ Pattern expectedPattern = expected[i];
+ String actualLine = actual[i];
+ Matcher matcher = expectedPattern.matcher(actualLine);
+ boolean matches = matcher.matches();
+ assertTrue(failMessage + System.lineSeparator() + "Line " + i + " '"
+ + actualLine + "' doesn't match expected pattern: "
+ + expectedPattern + System.lineSeparator() + "Expected: "
+ + Arrays.asList(expected) + ", actual: "
+ + Arrays.asList(actual),
+ matches);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index ed980b5006..2ef2cd2ddb 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.pgm
Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -14,49 +14,49 @@ Import-Package: javax.servlet;version="[3.1.0,5.0.0)",
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.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.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.archive;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.awtui;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.blame;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.diff;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.dircache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.gitrepo;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.io;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.server;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.server.fs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs.server.s3;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.merge;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.notes;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revplot;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.pack;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.ssh.jsch;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.sshd;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.0,6.3.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.1.1";
+Export-Package: org.eclipse.jgit.console;version="6.2.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="6.1.1";
+ org.eclipse.jgit.pgm;version="6.2.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util.io,
org.eclipse.jgit.awtui,
@@ -68,14 +68,14 @@ Export-Package: org.eclipse.jgit.console;version="6.1.1";
org.eclipse.jgit.treewalk,
org.eclipse.jgit.api,
javax.swing",
- org.eclipse.jgit.pgm.debug;version="6.1.1";
+ org.eclipse.jgit.pgm.debug;version="6.2.0";
uses:="org.eclipse.jgit.util.io,
org.eclipse.jgit.pgm,
org.eclipse.jetty.servlet",
- org.eclipse.jgit.pgm.internal;version="6.1.1";
+ org.eclipse.jgit.pgm.internal;version="6.2.0";
x-friends:="org.eclipse.jgit.pgm.test,
org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="6.1.1";
+ org.eclipse.jgit.pgm.opt;version="6.2.0";
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 0a5dd88040..fd88286810 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.pgm - Sources
Bundle-SymbolicName: org.eclipse.jgit.pgm.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="6.2.0.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 8c44764c63..ea1d1e3faa 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
@@ -25,6 +25,7 @@ org.eclipse.jgit.pgm.LsRemote
org.eclipse.jgit.pgm.LsTree
org.eclipse.jgit.pgm.Merge
org.eclipse.jgit.pgm.MergeBase
+org.eclipse.jgit.pgm.MergeTool
org.eclipse.jgit.pgm.Push
org.eclipse.jgit.pgm.ReceivePack
org.eclipse.jgit.pgm.Reflog
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index c189dc78c8..c06304d6df 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index fda0bf6ff4..b14531a1bd 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,9 +58,11 @@ couldNotCreateBranch=Could not create branch {0}: {1}
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}
+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 path ''{0}'' due to exception: {1}
+diffToolPromptToolName=This message is displayed because 'diff.tool' is not configured.\nSee 'git difftool --tool-help' or 'git help config' for more details.\n'git difftool' will now attempt to use one of the following tools:\n{0}\n
+diffToolUnknownToolName=Unknown diff tool '{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
@@ -91,6 +93,24 @@ listeningOn=Listening on {0}
logNoSignatureVerifier="No signature verifier available"
mergeConflict=CONFLICT(content): Merge conflict in {0}
mergeCheckoutConflict=error: Your local changes to the following files would be overwritten by merge:
+mergeToolHelpSetToFollowing=''git mergetool --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.
+mergeToolLaunch=Hit return to start merge resolution tool ({0}):
+mergeToolDied=local or remote cannot be found in cache, stopping at {0}
+mergeToolNoFiles=No files need merging
+mergeToolMerging=Merging:\n{0}
+mergeToolUnknownConflict=\nUnknown merge conflict for ''{0}'':
+mergeToolNormalConflict=\nNormal merge conflict for ''{0}'':\n '{'local'}': modified file\n '{'remote'}': modified file
+mergeToolMergeFailed=merge of {0} failed
+mergeToolExecutionError=excution error
+mergeToolFileUnchanged=\n{0} seems unchanged.
+mergeToolDeletedConflict=\nDeleted merge conflict for ''{0}'':
+mergeToolDeletedConflictByUs= {local}: deleted\n {remote}: modified file
+mergeToolDeletedConflictByThem= {local}: modified file\n {remote}: deleted
+mergeToolContinueUnresolvedPaths=\nContinue merging other unresolved paths [y/n]?
+mergeToolWasMergeSuccessfull=Was the merge successful [y/n]?
+mergeToolDeletedMergeDecision=Use (m)odified or (d)eleted file, or (a)bort?
+mergeToolPromptToolName=This message is displayed because 'merge.tool' is not configured.\nSee 'git mergetool --tool-help' or 'git help config' for more details.\n'git mergetool' will now attempt to use one of the following tools:\n{0}\n
+mergeToolUnknownToolName=Unknown merge tool '{0}'
mergeFailed=Automatic merge failed; fix conflicts and then commit the result
mergeCheckoutFailed=Please, commit your changes or stash them before you can merge.
mergeMadeBy=Merge made by the ''{0}'' strategy.
@@ -255,6 +275,7 @@ 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_MergeGuiTool=When git-mergetool is invoked with the -g or --gui option the default merge tool will be read from the configured merge.guitool variable instead of merge.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
@@ -303,6 +324,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_ToolForMerge=Use the merge resolution program specified by <tool>. Run git mergetool --tool-help for the list of valid <tool> settings.\nIf a merge resolution program is not specified, git mergetool will use the configuration variable merge.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
@@ -350,6 +372,7 @@ usage_date=date format, one of default, rfc, local, iso, short, raw (as defined
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_MergeTool=git-mergetool - Run merge conflict resolution tools to resolve merge conflicts.\nUse git mergetool to run one of several merge utilities to resolve merge conflicts. It is typically run after git merge.
usage_directoriesToExport=directories to export
usage_disableTheServiceInAllRepositories=disable the service in all repositories
usage_displayAListOfAllRegisteredJgitCommands=Display a list of all registered jgit commands
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
index 128881779b..3e6042afee 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2019, Tim Neumann <tim.neumann@advantest.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
@@ -11,25 +12,40 @@
package org.eclipse.jgit.pgm;
import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
+import java.io.FileOutputStream;
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.Optional;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.diff.ContentSource;
+import org.eclipse.jgit.diff.ContentSource.Pair;
import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffEntry.Side;
import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.dircache.DirCacheCheckout;
+import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.AmbiguousObjectException;
+import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.internal.diffmergetool.DiffTools;
import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
+import org.eclipse.jgit.internal.diffmergetool.FileElement;
+import org.eclipse.jgit.internal.diffmergetool.PromptContinueHandler;
+import org.eclipse.jgit.internal.diffmergetool.ToolException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
@@ -37,11 +53,16 @@ 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.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
-import org.eclipse.jgit.util.StringUtils;
+import org.eclipse.jgit.util.FS.ExecutionResult;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@@ -57,9 +78,13 @@ class DiffTool extends TextBuiltin {
@Argument(index = 1, metaVar = "metaVar_treeish")
private AbstractTreeIterator newTree;
+ private Optional<String> toolName = Optional.empty();
+
@Option(name = "--tool", aliases = {
"-t" }, metaVar = "metaVar_tool", usage = "usage_ToolForDiff")
- private String toolName;
+ void setToolName(String name) {
+ toolName = Optional.of(name);
+ }
@Option(name = "--cached", aliases = { "--staged" }, usage = "usage_cached")
private boolean cached;
@@ -79,16 +104,16 @@ class DiffTool extends TextBuiltin {
@Option(name = "--tool-help", usage = "usage_toolHelp")
private boolean toolHelp;
- private BooleanTriState gui = BooleanTriState.UNSET;
+ private boolean gui = false;
@Option(name = "--gui", aliases = { "-g" }, usage = "usage_DiffGuiTool")
void setGui(@SuppressWarnings("unused") boolean on) {
- gui = BooleanTriState.TRUE;
+ gui = true;
}
@Option(name = "--no-gui", usage = "usage_noGui")
void noGui(@SuppressWarnings("unused") boolean on) {
- gui = BooleanTriState.FALSE;
+ gui = false;
}
private BooleanTriState trustExitCode = BooleanTriState.UNSET;
@@ -106,11 +131,14 @@ class DiffTool extends TextBuiltin {
@Option(name = "--", metaVar = "metaVar_paths", handler = PathTreeFilterHandler.class)
private TreeFilter pathFilter = TreeFilter.ALL;
+ private BufferedReader inputReader;
+
@Override
protected void init(Repository repository, String gitDir) {
super.init(repository, gitDir);
diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
diffTools = new DiffTools(repository);
+ inputReader = new BufferedReader(new InputStreamReader(ins, StandardCharsets.UTF_8));
}
@Override
@@ -119,23 +147,12 @@ class DiffTool extends TextBuiltin {
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);
+ compare(files);
}
}
- outw.flush();
} catch (RevisionSyntaxException | IOException e) {
throw die(e.getMessage(), e);
} finally {
@@ -143,77 +160,127 @@ class DiffTool extends TextBuiltin {
}
}
- 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);
+ private void informUserNoTool(List<String> tools) {
+ try {
+ StringBuilder toolNames = new StringBuilder();
+ for (String name : tools) {
+ toolNames.append(name + " "); //$NON-NLS-1$
}
- 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));
+ outw.println(MessageFormat.format(
+ CLIText.get().diffToolPromptToolName, toolNames));
+ outw.flush();
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$
+ }
+ }
+
+ private class CountingPromptContinueHandler
+ implements PromptContinueHandler {
+ private final int fileIndex;
+
+ private final int fileCount;
+
+ private final String fileName;
+
+ public CountingPromptContinueHandler(int fileIndex, int fileCount,
+ String fileName) {
+ this.fileIndex = fileIndex;
+ this.fileCount = fileCount;
+ this.fileName = fileName;
+ }
+
+ @SuppressWarnings("boxing")
+ @Override
+ public boolean prompt(String toolToLaunchName) {
+ try {
+ boolean launchCompare = true;
+ outw.println(MessageFormat.format(CLIText.get().diffToolLaunch,
+ fileIndex, fileCount, fileName, toolToLaunchName)
+ + " "); //$NON-NLS-1$
+ outw.flush();
+ BufferedReader br = inputReader;
+ String line = null;
+ if ((line = br.readLine()) != null) {
+ if (!line.equalsIgnoreCase("Y")) { //$NON-NLS-1$
+ launchCompare = false;
}
- break;
- default:
- break;
}
- } else {
- break;
+ return launchCompare;
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$
}
}
}
- @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;
+ private void compare(List<DiffEntry> files) throws IOException {
+ ContentSource.Pair sourcePair = new ContentSource.Pair(source(oldTree),
+ source(newTree));
+ try {
+ for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) {
+ DiffEntry ent = files.get(fileIndex);
+
+ String filePath = ent.getNewPath();
+ if (filePath.equals(DiffEntry.DEV_NULL)) {
+ filePath = ent.getOldPath();
+ }
+
+ try {
+ FileElement local = createFileElement(
+ FileElement.Type.LOCAL, sourcePair, Side.OLD, ent);
+ FileElement remote = createFileElement(
+ FileElement.Type.REMOTE, sourcePair, Side.NEW, ent);
+
+ PromptContinueHandler promptContinueHandler = new CountingPromptContinueHandler(
+ fileIndex + 1, files.size(), filePath);
+
+ Optional<ExecutionResult> optionalResult = diffTools
+ .compare(local, remote, toolName, prompt, gui,
+ trustExitCode, promptContinueHandler,
+ this::informUserNoTool);
+
+ if (optionalResult.isPresent()) {
+ ExecutionResult result = optionalResult.get();
+ // TODO: check how to return the exit-code of the tool
+ // to jgit / java runtime ?
+ // int rc =...
+ outw.println(
+ new String(result.getStdout().toByteArray()));
+ outw.flush();
+ errw.println(
+ new String(result.getStderr().toByteArray()));
+ errw.flush();
+ }
+ } catch (ToolException e) {
+ outw.println(e.getResultStdout());
+ outw.flush();
+ errw.println(e.getMessage());
+ errw.flush();
+ throw die(MessageFormat.format(
+ CLIText.get().diffToolDied, filePath, e), e);
+ }
}
+ } finally {
+ sourcePair.close();
}
- return launchCompare;
}
private void showToolHelp() throws IOException {
+ Map<String, ExternalDiffTool> predefTools = diffTools
+ .getPredefinedTools(true);
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$
+ for (String name : predefTools.keySet()) {
+ if (predefTools.get(name).isAvailable()) {
+ availableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$
+ } else {
+ notAvailableToolNames.append(MessageFormat.format("\t\t{0}\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$
+ userToolNames.append(MessageFormat.format("\t\t{0}.cmd {1}\n", //$NON-NLS-1$
name, userTools.get(name).getCommand()));
}
outw.println(MessageFormat.format(
@@ -254,4 +321,54 @@ class DiffTool extends TextBuiltin {
return files;
}
+ private FileElement createFileElement(FileElement.Type elementType,
+ Pair pair, Side side, DiffEntry entry) throws NoWorkTreeException,
+ CorruptObjectException, IOException, ToolException {
+ String entryPath = side == Side.NEW ? entry.getNewPath()
+ : entry.getOldPath();
+ FileElement fileElement = new FileElement(entryPath, elementType,
+ db.getWorkTree());
+ if (!pair.isWorkingTreeSource(side) && !fileElement.isNullPath()) {
+ try (RevWalk revWalk = new RevWalk(db);
+ TreeWalk treeWalk = new TreeWalk(db,
+ revWalk.getObjectReader())) {
+ treeWalk.setFilter(
+ PathFilterGroup.createFromStrings(entryPath));
+ if (side == Side.NEW) {
+ newTree.reset();
+ treeWalk.addTree(newTree);
+ } else {
+ oldTree.reset();
+ treeWalk.addTree(oldTree);
+ }
+ if (treeWalk.next()) {
+ final EolStreamType eolStreamType = treeWalk
+ .getEolStreamType(CHECKOUT_OP);
+ final String filterCommand = treeWalk.getFilterCommand(
+ Constants.ATTR_FILTER_TYPE_SMUDGE);
+ WorkingTreeOptions opt = db.getConfig()
+ .get(WorkingTreeOptions.KEY);
+ CheckoutMetadata checkoutMetadata = new CheckoutMetadata(
+ eolStreamType, filterCommand);
+ DirCacheCheckout.getContent(db, entryPath,
+ checkoutMetadata, pair.open(side, entry), opt,
+ new FileOutputStream(
+ fileElement.createTempFile(null)));
+ } else {
+ throw new ToolException("Cannot find path '" + entryPath //$NON-NLS-1$
+ + "' in staging area!", //$NON-NLS-1$
+ null);
+ }
+ }
+ }
+ return fileElement;
+ }
+
+ private ContentSource source(AbstractTreeIterator iterator) {
+ if (iterator instanceof WorkingTreeIterator) {
+ return ContentSource.create((WorkingTreeIterator) iterator);
+ }
+ return ContentSource.create(db.newObjectReader());
+ }
+
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java
new file mode 100644
index 0000000000..2a411b81fe
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2019, Tim Neumann <tim.neumann@advantest.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.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.Status;
+import org.eclipse.jgit.api.StatusCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.diff.ContentSource;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheCheckout;
+import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
+import org.eclipse.jgit.internal.diffmergetool.ExternalMergeTool;
+import org.eclipse.jgit.internal.diffmergetool.FileElement;
+import org.eclipse.jgit.internal.diffmergetool.FileElement.Type;
+import org.eclipse.jgit.internal.diffmergetool.MergeTools;
+import org.eclipse.jgit.internal.diffmergetool.ToolException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
+import org.eclipse.jgit.lib.IndexDiff.StageState;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
+
+@Command(name = "mergetool", common = true, usage = "usage_MergeTool")
+class MergeTool extends TextBuiltin {
+ private MergeTools mergeTools;
+
+ private Optional<String> toolName = Optional.empty();
+
+ @Option(name = "--tool", aliases = {
+ "-t" }, metaVar = "metaVar_tool", usage = "usage_ToolForMerge")
+ void setToolName(String name) {
+ toolName = Optional.of(name);
+ }
+
+ 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 boolean gui = false;
+
+ @Option(name = "--gui", aliases = { "-g" }, usage = "usage_MergeGuiTool")
+ void setGui(@SuppressWarnings("unused") boolean on) {
+ gui = true;
+ }
+
+ @Option(name = "--no-gui", usage = "usage_noGui")
+ void noGui(@SuppressWarnings("unused") boolean on) {
+ gui = false;
+ }
+
+ @Argument(required = false, index = 0, metaVar = "metaVar_paths")
+ @Option(name = "--", metaVar = "metaVar_paths", handler = RestOfArgumentsHandler.class)
+ protected List<String> filterPaths;
+
+ private BufferedReader inputReader;
+
+ @Override
+ protected void init(Repository repository, String gitDir) {
+ super.init(repository, gitDir);
+ mergeTools = new MergeTools(repository);
+ inputReader = new BufferedReader(new InputStreamReader(ins));
+ }
+
+ enum MergeResult {
+ SUCCESSFUL, FAILED, ABORTED
+ }
+
+ @Override
+ protected void run() {
+ try {
+ if (toolHelp) {
+ showToolHelp();
+ } else {
+ // get the changed files
+ Map<String, StageState> files = getFiles();
+ if (files.size() > 0) {
+ merge(files);
+ } else {
+ outw.println(CLIText.get().mergeToolNoFiles);
+ }
+ }
+ outw.flush();
+ } catch (Exception e) {
+ throw die(e.getMessage(), e);
+ }
+ }
+
+ private void informUserNoTool(List<String> tools) {
+ try {
+ StringBuilder toolNames = new StringBuilder();
+ for (String name : tools) {
+ toolNames.append(name + " "); //$NON-NLS-1$
+ }
+ outw.println(MessageFormat
+ .format(CLIText.get().mergeToolPromptToolName, toolNames));
+ outw.flush();
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$
+ }
+ }
+
+ private void merge(Map<String, StageState> files) throws Exception {
+ // sort file names
+ List<String> mergedFilePaths = new ArrayList<>(files.keySet());
+ Collections.sort(mergedFilePaths);
+ // show the files
+ StringBuilder mergedFiles = new StringBuilder();
+ for (String mergedFilePath : mergedFilePaths) {
+ mergedFiles.append(MessageFormat.format("{0}\n", mergedFilePath)); //$NON-NLS-1$
+ }
+ outw.println(MessageFormat.format(CLIText.get().mergeToolMerging,
+ mergedFiles));
+ outw.flush();
+ boolean showPrompt = mergeTools.isInteractive();
+ if (prompt != BooleanTriState.UNSET) {
+ showPrompt = prompt == BooleanTriState.TRUE;
+ }
+ // merge the files
+ MergeResult mergeResult = MergeResult.SUCCESSFUL;
+ for (String mergedFilePath : mergedFilePaths) {
+ // if last merge failed...
+ if (mergeResult == MergeResult.FAILED) {
+ // check if user wants to continue
+ if (showPrompt && !isContinueUnresolvedPaths()) {
+ mergeResult = MergeResult.ABORTED;
+ }
+ }
+ // aborted ?
+ if (mergeResult == MergeResult.ABORTED) {
+ break;
+ }
+ // get file stage state and merge
+ StageState fileState = files.get(mergedFilePath);
+ if (fileState == StageState.BOTH_MODIFIED) {
+ mergeResult = mergeModified(mergedFilePath, showPrompt);
+ } else if ((fileState == StageState.DELETED_BY_US)
+ || (fileState == StageState.DELETED_BY_THEM)) {
+ mergeResult = mergeDeleted(mergedFilePath,
+ fileState == StageState.DELETED_BY_US);
+ } else {
+ outw.println(MessageFormat.format(
+ CLIText.get().mergeToolUnknownConflict,
+ mergedFilePath));
+ mergeResult = MergeResult.ABORTED;
+ }
+ }
+ }
+
+ private MergeResult mergeModified(String mergedFilePath, boolean showPrompt)
+ throws Exception {
+ outw.println(MessageFormat.format(CLIText.get().mergeToolNormalConflict,
+ mergedFilePath));
+ outw.flush();
+ boolean isMergeSuccessful = true;
+ ContentSource baseSource = ContentSource.create(db.newObjectReader());
+ ContentSource localSource = ContentSource.create(db.newObjectReader());
+ ContentSource remoteSource = ContentSource.create(db.newObjectReader());
+ // temporary directory if mergetool.writeToTemp == true
+ File tempDir = mergeTools.createTempDirectory();
+ // the parent directory for temp files (can be same as tempDir or just
+ // the worktree dir)
+ File tempFilesParent = tempDir != null ? tempDir : db.getWorkTree();
+ try {
+ FileElement base = null;
+ FileElement local = null;
+ FileElement remote = null;
+ FileElement merged = new FileElement(mergedFilePath, Type.MERGED,
+ db.getWorkTree());
+ DirCache cache = db.readDirCache();
+ try (RevWalk revWalk = new RevWalk(db);
+ TreeWalk treeWalk = new TreeWalk(db,
+ revWalk.getObjectReader())) {
+ treeWalk.setFilter(
+ PathFilterGroup.createFromStrings(mergedFilePath));
+ DirCacheIterator cacheIter = new DirCacheIterator(cache);
+ treeWalk.addTree(cacheIter);
+ while (treeWalk.next()) {
+ if (treeWalk.isSubtree()) {
+ treeWalk.enterSubtree();
+ continue;
+ }
+ final EolStreamType eolStreamType = treeWalk
+ .getEolStreamType(CHECKOUT_OP);
+ final String filterCommand = treeWalk.getFilterCommand(
+ Constants.ATTR_FILTER_TYPE_SMUDGE);
+ WorkingTreeOptions opt = db.getConfig()
+ .get(WorkingTreeOptions.KEY);
+ CheckoutMetadata checkoutMetadata = new CheckoutMetadata(
+ eolStreamType, filterCommand);
+ DirCacheEntry entry = treeWalk
+ .getTree(DirCacheIterator.class).getDirCacheEntry();
+ if (entry == null) {
+ continue;
+ }
+ ObjectId id = entry.getObjectId();
+ switch (entry.getStage()) {
+ case DirCacheEntry.STAGE_1:
+ base = new FileElement(mergedFilePath, Type.BASE);
+ DirCacheCheckout.getContent(db, mergedFilePath,
+ checkoutMetadata,
+ baseSource.open(mergedFilePath, id), opt,
+ new FileOutputStream(
+ base.createTempFile(tempFilesParent)));
+ break;
+ case DirCacheEntry.STAGE_2:
+ local = new FileElement(mergedFilePath, Type.LOCAL);
+ DirCacheCheckout.getContent(db, mergedFilePath,
+ checkoutMetadata,
+ localSource.open(mergedFilePath, id), opt,
+ new FileOutputStream(
+ local.createTempFile(tempFilesParent)));
+ break;
+ case DirCacheEntry.STAGE_3:
+ remote = new FileElement(mergedFilePath, Type.REMOTE);
+ DirCacheCheckout.getContent(db, mergedFilePath,
+ checkoutMetadata,
+ remoteSource.open(mergedFilePath, id), opt,
+ new FileOutputStream(remote
+ .createTempFile(tempFilesParent)));
+ break;
+ }
+ }
+ }
+ if ((local == null) || (remote == null)) {
+ throw die(MessageFormat.format(CLIText.get().mergeToolDied,
+ mergedFilePath));
+ }
+ long modifiedBefore = merged.getFile().lastModified();
+ try {
+ // TODO: check how to return the exit-code of the
+ // tool to jgit / java runtime ?
+ // int rc =...
+ Optional<ExecutionResult> optionalResult = mergeTools.merge(
+ local, remote, merged, base, tempDir, toolName, prompt,
+ gui, this::promptForLaunch, this::informUserNoTool);
+ if (optionalResult.isPresent()) {
+ ExecutionResult result = optionalResult.get();
+ outw.println(new String(result.getStdout().toByteArray()));
+ outw.flush();
+ errw.println(new String(result.getStderr().toByteArray()));
+ errw.flush();
+ } else {
+ return MergeResult.ABORTED;
+ }
+ } catch (ToolException e) {
+ isMergeSuccessful = false;
+ outw.println(e.getResultStdout());
+ outw.flush();
+ errw.println(e.getMessage());
+ errw.println(MessageFormat.format(
+ CLIText.get().mergeToolMergeFailed, mergedFilePath));
+ errw.flush();
+ if (e.isCommandExecutionError()) {
+ throw die(CLIText.get().mergeToolExecutionError, e);
+ }
+ }
+ // if merge was successful check file modified
+ if (isMergeSuccessful) {
+ long modifiedAfter = merged.getFile().lastModified();
+ if (modifiedBefore == modifiedAfter) {
+ outw.println(MessageFormat.format(
+ CLIText.get().mergeToolFileUnchanged,
+ mergedFilePath));
+ isMergeSuccessful = !showPrompt || isMergeSuccessful();
+ }
+ }
+ // if automatically or manually successful
+ // -> add the file to the index
+ if (isMergeSuccessful) {
+ addFile(mergedFilePath);
+ }
+ } finally {
+ baseSource.close();
+ localSource.close();
+ remoteSource.close();
+ }
+ return isMergeSuccessful ? MergeResult.SUCCESSFUL : MergeResult.FAILED;
+ }
+
+ private MergeResult mergeDeleted(String mergedFilePath, boolean deletedByUs)
+ throws Exception {
+ outw.println(MessageFormat.format(CLIText.get().mergeToolFileUnchanged,
+ mergedFilePath));
+ if (deletedByUs) {
+ outw.println(CLIText.get().mergeToolDeletedConflictByUs);
+ } else {
+ outw.println(CLIText.get().mergeToolDeletedConflictByThem);
+ }
+ int mergeDecision = getDeletedMergeDecision();
+ if (mergeDecision == 1) {
+ // add modified file
+ addFile(mergedFilePath);
+ } else if (mergeDecision == -1) {
+ // remove deleted file
+ rmFile(mergedFilePath);
+ } else {
+ return MergeResult.ABORTED;
+ }
+ return MergeResult.SUCCESSFUL;
+ }
+
+ private void addFile(String fileName) throws Exception {
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(fileName).call();
+ }
+ }
+
+ private void rmFile(String fileName) throws Exception {
+ try (Git git = new Git(db)) {
+ git.rm().addFilepattern(fileName).call();
+ }
+ }
+
+ private boolean hasUserAccepted(String message) throws IOException {
+ boolean yes = true;
+ outw.print(message + " "); //$NON-NLS-1$
+ outw.flush();
+ BufferedReader br = inputReader;
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ if (line.equalsIgnoreCase("y")) { //$NON-NLS-1$
+ yes = true;
+ break;
+ } else if (line.equalsIgnoreCase("n")) { //$NON-NLS-1$
+ yes = false;
+ break;
+ }
+ outw.print(message);
+ outw.flush();
+ }
+ return yes;
+ }
+
+ private boolean isContinueUnresolvedPaths() throws IOException {
+ return hasUserAccepted(CLIText.get().mergeToolContinueUnresolvedPaths);
+ }
+
+ private boolean isMergeSuccessful() throws IOException {
+ return hasUserAccepted(CLIText.get().mergeToolWasMergeSuccessfull);
+ }
+
+ private boolean promptForLaunch(String toolNamePrompt) {
+ try {
+ boolean launch = true;
+ outw.print(MessageFormat.format(CLIText.get().mergeToolLaunch,
+ toolNamePrompt) + " "); //$NON-NLS-1$
+ outw.flush();
+ BufferedReader br = inputReader;
+ String line = null;
+ if ((line = br.readLine()) != null) {
+ if (!line.equalsIgnoreCase("y") && !line.equalsIgnoreCase("")) { //$NON-NLS-1$ //$NON-NLS-2$
+ launch = false;
+ }
+ }
+ return launch;
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot output text", e); //$NON-NLS-1$
+ }
+ }
+
+ private int getDeletedMergeDecision() throws IOException {
+ int ret = 0; // abort
+ final String message = CLIText.get().mergeToolDeletedMergeDecision
+ + " "; //$NON-NLS-1$
+ outw.print(message);
+ outw.flush();
+ BufferedReader br = inputReader;
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ if (line.equalsIgnoreCase("m")) { //$NON-NLS-1$
+ ret = 1; // modified
+ break;
+ } else if (line.equalsIgnoreCase("d")) { //$NON-NLS-1$
+ ret = -1; // deleted
+ break;
+ } else if (line.equalsIgnoreCase("a")) { //$NON-NLS-1$
+ break;
+ }
+ outw.print(message);
+ outw.flush();
+ }
+ return ret;
+ }
+
+ private void showToolHelp() throws IOException {
+ Map<String, ExternalMergeTool> predefTools = mergeTools
+ .getPredefinedTools(true);
+ StringBuilder availableToolNames = new StringBuilder();
+ StringBuilder notAvailableToolNames = new StringBuilder();
+ for (String name : predefTools.keySet()) {
+ if (predefTools.get(name).isAvailable()) {
+ availableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$
+ } else {
+ notAvailableToolNames.append(MessageFormat.format("\t\t{0}\n", name)); //$NON-NLS-1$
+ }
+ }
+ StringBuilder userToolNames = new StringBuilder();
+ Map<String, ExternalMergeTool> userTools = mergeTools
+ .getUserDefinedTools();
+ for (String name : userTools.keySet()) {
+ userToolNames.append(MessageFormat.format("\t\t{0}.cmd {1}\n", //$NON-NLS-1$
+ name, userTools.get(name).getCommand()));
+ }
+ outw.println(MessageFormat.format(
+ CLIText.get().mergeToolHelpSetToFollowing, availableToolNames,
+ userToolNames, notAvailableToolNames));
+ }
+
+ private Map<String, StageState> getFiles() throws RevisionSyntaxException,
+ NoWorkTreeException, GitAPIException {
+ Map<String, StageState> files = new TreeMap<>();
+ try (Git git = new Git(db)) {
+ StatusCommand statusCommand = git.status();
+ if (filterPaths != null && filterPaths.size() > 0) {
+ for (String path : filterPaths) {
+ statusCommand.addPath(path);
+ }
+ }
+ Status status = statusCommand.call();
+ files = status.getConflictingStageState();
+ }
+ return files;
+ }
+
+}
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 7fe5b0fa45..e06f150e51 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
@@ -139,6 +139,8 @@ public class CLIText extends TranslationBundle {
/***/ public String diffToolHelpSetToFollowing;
/***/ public String diffToolLaunch;
/***/ public String diffToolDied;
+ /***/ public String diffToolPromptToolName;
+ /***/ public String diffToolUnknownToolName;
/***/ public String doesNotExist;
/***/ public String dontOverwriteLocalChanges;
/***/ public String everythingUpToDate;
@@ -169,6 +171,24 @@ public class CLIText extends TranslationBundle {
/***/ public String logNoSignatureVerifier;
/***/ public String mergeCheckoutConflict;
/***/ public String mergeConflict;
+ /***/ public String mergeToolHelpSetToFollowing;
+ /***/ public String mergeToolLaunch;
+ /***/ public String mergeToolDied;
+ /***/ public String mergeToolNoFiles;
+ /***/ public String mergeToolMerging;
+ /***/ public String mergeToolUnknownConflict;
+ /***/ public String mergeToolNormalConflict;
+ /***/ public String mergeToolMergeFailed;
+ /***/ public String mergeToolExecutionError;
+ /***/ public String mergeToolFileUnchanged;
+ /***/ public String mergeToolDeletedConflict;
+ /***/ public String mergeToolDeletedConflictByUs;
+ /***/ public String mergeToolDeletedConflictByThem;
+ /***/ public String mergeToolContinueUnresolvedPaths;
+ /***/ public String mergeToolWasMergeSuccessfull;
+ /***/ public String mergeToolDeletedMergeDecision;
+ /***/ public String mergeToolPromptToolName;
+ /***/ public String mergeToolUnknownToolName;
/***/ public String mergeFailed;
/***/ public String mergeCheckoutFailed;
/***/ public String mergeMadeBy;
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 1a5746df00..64f6861bd8 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,16 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent;singleton:=true
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
+Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
-Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[6.1.1,6.2.0)"
+Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[6.2.0,6.3.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.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)"
+Import-Package: org.eclipse.jgit.transport.sshd;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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.1.1";x-internal:=true
+Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="6.2.0";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 d06e6b172f..57f00a94e6 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-ManifestVersion: 2
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.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache.agent/pom.xml b/org.eclipse.jgit.ssh.apache.agent/pom.xml
index 77b9c952fb..262b9c6476 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.apache.agent</artifactId>
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
index 7bad90f24f..81c653722f 100644
--- 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
@@ -90,7 +90,7 @@ public class WinPipeConnector extends AbstractConnector {
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) {
+ if (file == null || WinBase.INVALID_HANDLE_VALUE.equals(file)) {
int errorCode = libs.kernel.GetLastError();
if (errorCode == WinError.ERROR_FILE_NOT_FOUND
&& CANONICAL_PIPE_NAME.equalsIgnoreCase(pipeName)) {
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 411d43cf8a..794a585731 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -21,16 +21,16 @@ Import-Package: org.apache.sshd.client.config.hosts;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.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit.ssh;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.sshd;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.sshd.agent;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 3e98e33371..6f9dcac175 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 3d7c7651c1..a8fcca7b8e 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2020 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
@@ -789,4 +789,76 @@ public class ApacheSshTest extends SshTestBase {
session.disconnect();
}
}
+
+ private void verifyAuthLog(String message, String first) {
+ assertTrue(message.contains(System.lineSeparator()));
+ String[] lines = message.split(System.lineSeparator());
+ int pubkeyIndex = -1;
+ int passwordIndex = -1;
+ for (int i = 0; i < lines.length; i++) {
+ String line = lines[i];
+ if (i == 0) {
+ assertTrue(line.contains(first));
+ }
+ if (line.contains("publickey:")) {
+ if (pubkeyIndex < 0) {
+ pubkeyIndex = i;
+ assertTrue(line.contains("/userkey"));
+ }
+ } else if (line.contains("password:")) {
+ if (passwordIndex < 0) {
+ passwordIndex = i;
+ assertTrue(line.contains("attempt 1"));
+ }
+ }
+ }
+ assertTrue(pubkeyIndex > 0 && passwordIndex > 0);
+ assertTrue(pubkeyIndex < passwordIndex);
+ }
+
+ @Test
+ public void testAuthFailureMessageCancel() throws Exception {
+ File userKey = new File(getTemporaryDirectory(), "userkey");
+ copyTestResource("id_ed25519", userKey);
+ File publicKey = new File(getTemporaryDirectory(), "userkey.pub");
+ copyTestResource("id_ed25519.pub", publicKey);
+ // Don't set this as the user's key; we do want to try with a wrong key.
+ server.enablePasswordAuthentication();
+ TestCredentialsProvider provider = new TestCredentialsProvider(
+ "wrongpass");
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://git/doesntmatter", defaultCloneDir,
+ provider, //
+ "Host git", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + userKey.getAbsolutePath(), //
+ "PreferredAuthentications publickey,password"));
+ verifyAuthLog(e.getMessage(), "canceled");
+ }
+
+ @Test
+ public void testAuthFailureMessage() throws Exception {
+ File userKey = new File(getTemporaryDirectory(), "userkey");
+ copyTestResource("id_ed25519", userKey);
+ File publicKey = new File(getTemporaryDirectory(), "userkey.pub");
+ copyTestResource("id_ed25519.pub", publicKey);
+ // Don't set this as the user's key; we do want to try with a wrong key.
+ server.enablePasswordAuthentication();
+ // Enough passwords not to cancel authentication
+ TestCredentialsProvider provider = new TestCredentialsProvider(
+ "wrongpass", "wrongpass", "wrongpass");
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://git/doesntmatter", defaultCloneDir,
+ provider, //
+ "Host git", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + userKey.getAbsolutePath(), //
+ "PreferredAuthentications publickey,password"));
+ verifyAuthLog(e.getMessage(), "log in");
+ }
+
}
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 73feaeca85..041f0ce987 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-SymbolicName: org.eclipse.jgit.ssh.apache
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Export-Package: org.eclipse.jgit.internal.transport.sshd;version="6.1.1";x-internal:=true;
+Export-Package: org.eclipse.jgit.internal.transport.sshd;version="6.2.0";x-internal:=true;
uses:="org.apache.sshd.client,
org.apache.sshd.client.auth,
org.apache.sshd.client.auth.keyboard,
@@ -23,17 +23,17 @@ Export-Package: org.eclipse.jgit.internal.transport.sshd;version="6.1.1";x-inter
org.apache.sshd.common.signature,
org.apache.sshd.common.util.buffer,
org.eclipse.jgit.transport",
- 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";
+ org.eclipse.jgit.internal.transport.sshd.agent;version="6.2.0";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.auth;version="6.2.0";x-internal:=true,
+ org.eclipse.jgit.internal.transport.sshd.proxy;version="6.2.0";x-friends:="org.eclipse.jgit.ssh.apache.test",
+ org.eclipse.jgit.transport.sshd;version="6.2.0";
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.1.1"
+ org.eclipse.jgit.transport.sshd.agent;version="6.2.0"
Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)",
org.apache.sshd.agent;version="[2.8.0,2.9.0)",
org.apache.sshd.client;version="[2.8.0,2.9.0)",
@@ -86,12 +86,12 @@ Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.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.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.fnmatch;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 9fefa6e74c..76a9fd5ab6 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.ssh.apache - Sources
Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml
index 674c7a49e5..106bc38e3c 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.apache</artifactId>
@@ -50,16 +50,6 @@
<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.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 4f735bab34..c676221800 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,22 @@
authenticationCanceled=SSH authentication canceled: no password given
authenticationOnClosedSession=Authentication canceled: session is already closing or closed
+authGssApiAttempt={0}: trying mechanism OID {1}
+authGssApiExhausted={0}: no more mechanisms to try
+authGssApiFailure={0}: server refused authentication; mechanism {1}
+authGssApiNotTried={0}: not tried
+authGssApiPartialSuccess={0}: partial success with mechanism OID {1}, continue with authentication methods {2}
+authPasswordAttempt={0}: attempt {1}
+authPasswordChangeAttempt={0}: attempt {1} with password change
+authPasswordExhausted={0}: no more attempts
+authPasswordFailure={0}: server refused (wrong password)
+authPasswordNotTried={0}: not tried
+authPasswordPartialSuccess={0}: partial success, continue with authentication methods {1}
+authPubkeyAttempt={0}: trying {1} key {2} with signature type {3}
+authPubkeyAttemptAgent={0}: trying {1} key {2} from SSH agent with signature type {3}
+authPubkeyExhausted={0}: no more keys to try
+authPubkeyFailure={0}: server refused {1} key {2}
+authPubkeyNoKeys={0}: no keys to try
+authPubkeyPartialSuccess={0}: partial success for {1} key {2}, continue with authentication methods {3}
cannotReadPublicKey=Cannot read public key from file {0}
closeListenerFailed=Ssh session close listener failed
configInvalidPath=Invalid path in ssh config key {0}: {1}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationLogger.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationLogger.java
new file mode 100644
index 0000000000..add79b35c9
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationLogger.java
@@ -0,0 +1,238 @@
+/*
+ * 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.internal.transport.sshd;
+
+import static org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider.getKeyId;
+
+import java.security.KeyPair;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.client.auth.password.PasswordAuthenticationReporter;
+import org.apache.sshd.client.auth.password.UserAuthPassword;
+import org.apache.sshd.client.auth.pubkey.PublicKeyAuthenticationReporter;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.config.keys.KeyUtils;
+
+/**
+ * Provides a log of authentication attempts for a {@link ClientSession}.
+ */
+public class AuthenticationLogger {
+
+ private final List<String> messages = new ArrayList<>();
+
+ // We're interested in this log only in the failure case, so we don't need
+ // to log authentication success.
+
+ private final PublicKeyAuthenticationReporter pubkeyLogger = new PublicKeyAuthenticationReporter() {
+
+ private boolean hasAttempts;
+
+ @Override
+ public void signalAuthenticationAttempt(ClientSession session,
+ String service, KeyPair identity, String signature)
+ throws Exception {
+ hasAttempts = true;
+ String message;
+ if (identity.getPrivate() == null) {
+ // SSH agent key
+ message = MessageFormat.format(
+ SshdText.get().authPubkeyAttemptAgent,
+ UserAuthPublicKey.NAME, KeyUtils.getKeyType(identity),
+ getKeyId(session, identity), signature);
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authPubkeyAttempt,
+ UserAuthPublicKey.NAME, KeyUtils.getKeyType(identity),
+ getKeyId(session, identity), signature);
+ }
+ messages.add(message);
+ }
+
+ @Override
+ public void signalAuthenticationExhausted(ClientSession session,
+ String service) throws Exception {
+ String message;
+ if (hasAttempts) {
+ message = MessageFormat.format(
+ SshdText.get().authPubkeyExhausted,
+ UserAuthPublicKey.NAME);
+ } else {
+ message = MessageFormat.format(SshdText.get().authPubkeyNoKeys,
+ UserAuthPublicKey.NAME);
+ }
+ messages.add(message);
+ hasAttempts = false;
+ }
+
+ @Override
+ public void signalAuthenticationFailure(ClientSession session,
+ String service, KeyPair identity, boolean partial,
+ List<String> serverMethods) throws Exception {
+ String message;
+ if (partial) {
+ message = MessageFormat.format(
+ SshdText.get().authPubkeyPartialSuccess,
+ UserAuthPublicKey.NAME, KeyUtils.getKeyType(identity),
+ getKeyId(session, identity), serverMethods);
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authPubkeyFailure,
+ UserAuthPublicKey.NAME, KeyUtils.getKeyType(identity),
+ getKeyId(session, identity));
+ }
+ messages.add(message);
+ }
+ };
+
+ private final PasswordAuthenticationReporter passwordLogger = new PasswordAuthenticationReporter() {
+
+ private int attempts;
+
+ @Override
+ public void signalAuthenticationAttempt(ClientSession session,
+ String service, String oldPassword, boolean modified,
+ String newPassword) throws Exception {
+ attempts++;
+ String message;
+ if (modified) {
+ message = MessageFormat.format(
+ SshdText.get().authPasswordChangeAttempt,
+ UserAuthPassword.NAME, Integer.valueOf(attempts));
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authPasswordAttempt,
+ UserAuthPassword.NAME, Integer.valueOf(attempts));
+ }
+ messages.add(message);
+ }
+
+ @Override
+ public void signalAuthenticationExhausted(ClientSession session,
+ String service) throws Exception {
+ String message;
+ if (attempts > 0) {
+ message = MessageFormat.format(
+ SshdText.get().authPasswordExhausted,
+ UserAuthPassword.NAME);
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authPasswordNotTried,
+ UserAuthPassword.NAME);
+ }
+ messages.add(message);
+ attempts = 0;
+ }
+
+ @Override
+ public void signalAuthenticationFailure(ClientSession session,
+ String service, String password, boolean partial,
+ List<String> serverMethods) throws Exception {
+ String message;
+ if (partial) {
+ message = MessageFormat.format(
+ SshdText.get().authPasswordPartialSuccess,
+ UserAuthPassword.NAME, serverMethods);
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authPasswordFailure,
+ UserAuthPassword.NAME);
+ }
+ messages.add(message);
+ }
+ };
+
+ private final GssApiWithMicAuthenticationReporter gssLogger = new GssApiWithMicAuthenticationReporter() {
+
+ private boolean hasAttempts;
+
+ @Override
+ public void signalAuthenticationAttempt(ClientSession session,
+ String service, String mechanism) {
+ hasAttempts = true;
+ String message = MessageFormat.format(
+ SshdText.get().authGssApiAttempt,
+ GssApiWithMicAuthFactory.NAME, mechanism);
+ messages.add(message);
+ }
+
+ @Override
+ public void signalAuthenticationExhausted(ClientSession session,
+ String service) {
+ String message;
+ if (hasAttempts) {
+ message = MessageFormat.format(
+ SshdText.get().authGssApiExhausted,
+ GssApiWithMicAuthFactory.NAME);
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authGssApiNotTried,
+ GssApiWithMicAuthFactory.NAME);
+ }
+ messages.add(message);
+ hasAttempts = false;
+ }
+
+ @Override
+ public void signalAuthenticationFailure(ClientSession session,
+ String service, String mechanism, boolean partial,
+ List<String> serverMethods) {
+ String message;
+ if (partial) {
+ message = MessageFormat.format(
+ SshdText.get().authGssApiPartialSuccess,
+ GssApiWithMicAuthFactory.NAME, mechanism,
+ serverMethods);
+ } else {
+ message = MessageFormat.format(
+ SshdText.get().authGssApiFailure,
+ GssApiWithMicAuthFactory.NAME, mechanism);
+ }
+ messages.add(message);
+ }
+ };
+
+ /**
+ * Creates a new {@link AuthenticationLogger} and configures the
+ * {@link ClientSession} to report authentication attempts through this
+ * instance.
+ *
+ * @param session
+ * to configure
+ */
+ public AuthenticationLogger(ClientSession session) {
+ session.setPublicKeyAuthenticationReporter(pubkeyLogger);
+ session.setPasswordAuthenticationReporter(passwordLogger);
+ session.setAttribute(
+ GssApiWithMicAuthenticationReporter.GSS_AUTHENTICATION_REPORTER,
+ gssLogger);
+ // TODO: keyboard-interactive? sshd 2.8.0 has no callback
+ // interface for it.
+ }
+
+ /**
+ * Retrieves the log messages for the authentication attempts.
+ *
+ * @return the messages as an unmodifiable list
+ */
+ public List<String> getLog() {
+ return Collections.unmodifiableList(messages);
+ }
+
+ /**
+ * Drops all previously recorded log messages.
+ */
+ public void clear() {
+ messages.clear();
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
index 79b3637caa..cbd6a64140 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/CachingKeyPairProvider.java
@@ -1,5 +1,5 @@
/*
- * 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
@@ -11,6 +11,7 @@ package org.eclipse.jgit.internal.transport.sshd;
import static java.text.MessageFormat.format;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@@ -19,18 +20,24 @@ import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.PrivateKey;
+import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.CancellationException;
import javax.security.auth.DestroyFailedException;
+import org.apache.sshd.common.AttributeRepository.AttributeKey;
+import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.common.util.io.resource.IoResource;
@@ -43,6 +50,14 @@ import org.eclipse.jgit.transport.sshd.KeyCache;
public class CachingKeyPairProvider extends FileKeyPairProvider
implements Iterable<KeyPair> {
+ /**
+ * An attribute set on the {@link SessionContext} recording loaded keys by
+ * fingerprint. This enables us to provide nicer output by showing key
+ * paths, if possible. Users can identify key identities used easier by
+ * filename than by fingerprint.
+ */
+ public static final AttributeKey<Map<String, Path>> KEY_PATHS_BY_FINGERPRINT = new AttributeKey<>();
+
private final KeyCache cache;
/**
@@ -78,6 +93,33 @@ public class CachingKeyPairProvider extends FileKeyPairProvider
return () -> iterator(session);
}
+ static String getKeyId(ClientSession session, KeyPair identity) {
+ String fingerprint = KeyUtils.getFingerPrint(identity.getPublic());
+ Map<String, Path> registered = session
+ .getAttribute(KEY_PATHS_BY_FINGERPRINT);
+ if (registered != null) {
+ Path path = registered.get(fingerprint);
+ if (path != null) {
+ Path home = session
+ .resolveAttribute(JGitSshClient.HOME_DIRECTORY);
+ if (home != null && path.startsWith(home)) {
+ try {
+ path = home.relativize(path);
+ String pathString = path.toString();
+ if (!pathString.isEmpty()) {
+ return "~" + File.separator + pathString; //$NON-NLS-1$
+ }
+ } catch (IllegalArgumentException e) {
+ // Cannot be relativized. Ignore, and work with the
+ // original path
+ }
+ }
+ return path.toString();
+ }
+ }
+ return fingerprint;
+ }
+
private KeyPair loadKey(SessionContext session, Path path)
throws IOException, GeneralSecurityException {
if (!Files.exists(path)) {
@@ -123,13 +165,23 @@ public class CachingKeyPairProvider extends FileKeyPairProvider
SshdText.get().identityFileUnsupportedFormat, path));
}
KeyPair result = keys.next();
+ PublicKey pk = result.getPublic();
+ if (pk != null) {
+ Map<String, Path> registered = session
+ .getAttribute(KEY_PATHS_BY_FINGERPRINT);
+ if (registered == null) {
+ registered = new HashMap<>();
+ session.setAttribute(KEY_PATHS_BY_FINGERPRINT, registered);
+ }
+ registered.put(KeyUtils.getFingerPrint(pk), path);
+ }
if (keys.hasNext()) {
log.warn(format(SshdText.get().identityFileMultipleKeys, path));
keys.forEachRemaining(k -> {
- PrivateKey pk = k.getPrivate();
- if (pk != null) {
+ PrivateKey priv = k.getPrivate();
+ if (priv != null) {
try {
- pk.destroy();
+ priv.destroy();
} catch (DestroyFailedException e) {
// Ignore
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthentication.java
index c3cac0c1df..df01db316b 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthentication.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthentication.java
@@ -1,5 +1,5 @@
/*
- * 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
@@ -18,6 +18,7 @@ import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import org.apache.sshd.client.auth.AbstractUserAuth;
import org.apache.sshd.client.session.ClientSession;
@@ -71,7 +72,10 @@ public class GssApiWithMicAuthentication extends AbstractUserAuth {
if (context != null) {
close(false);
}
+ GssApiWithMicAuthenticationReporter reporter = session.getAttribute(
+ GssApiWithMicAuthenticationReporter.GSS_AUTHENTICATION_REPORTER);
if (!nextMechanism.hasNext()) {
+ reporter.signalAuthenticationExhausted(session, service);
return false;
}
state = ProtocolState.STARTED;
@@ -79,6 +83,7 @@ public class GssApiWithMicAuthentication extends AbstractUserAuth {
// RFC 4462 states that SPNEGO must not be used with ssh
while (GssApiMechanisms.SPNEGO.equals(currentMechanism)) {
if (!nextMechanism.hasNext()) {
+ reporter.signalAuthenticationExhausted(session, service);
return false;
}
currentMechanism = nextMechanism.next();
@@ -102,6 +107,10 @@ public class GssApiWithMicAuthentication extends AbstractUserAuth {
state = ProtocolState.FAILED;
return false;
}
+ if (reporter != null) {
+ reporter.signalAuthenticationAttempt(session, service,
+ currentMechanism.toString());
+ }
Buffer buffer = session
.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
buffer.putString(session.getUsername());
@@ -246,4 +255,26 @@ public class GssApiWithMicAuthentication extends AbstractUserAuth {
return false;
}
+ @Override
+ public void signalAuthMethodSuccess(ClientSession session, String service,
+ Buffer buffer) throws Exception {
+ GssApiWithMicAuthenticationReporter reporter = session.getAttribute(
+ GssApiWithMicAuthenticationReporter.GSS_AUTHENTICATION_REPORTER);
+ if (reporter != null) {
+ reporter.signalAuthenticationSuccess(session, service,
+ currentMechanism.toString());
+ }
+ }
+
+ @Override
+ public void signalAuthMethodFailure(ClientSession session, String service,
+ boolean partial, List<String> serverMethods, Buffer buffer)
+ throws Exception {
+ GssApiWithMicAuthenticationReporter reporter = session.getAttribute(
+ GssApiWithMicAuthenticationReporter.GSS_AUTHENTICATION_REPORTER);
+ if (reporter != null) {
+ reporter.signalAuthenticationFailure(session, service,
+ currentMechanism.toString(), partial, serverMethods);
+ }
+ }
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthenticationReporter.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthenticationReporter.java
new file mode 100644
index 0000000000..201a131650
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/GssApiWithMicAuthenticationReporter.java
@@ -0,0 +1,93 @@
+/*
+ * 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.internal.transport.sshd;
+
+import java.util.List;
+
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.AttributeRepository.AttributeKey;
+
+/**
+ * Callback interface for recording authentication state in
+ * {@link GssApiWithMicAuthentication}.
+ */
+public interface GssApiWithMicAuthenticationReporter {
+
+ /**
+ * An {@link AttributeKey} for a {@link ClientSession} holding the
+ * {@link GssApiWithMicAuthenticationReporter}.
+ */
+ static final AttributeKey<GssApiWithMicAuthenticationReporter> GSS_AUTHENTICATION_REPORTER = new AttributeKey<>();
+
+ /**
+ * Called when a new authentication attempt is made.
+ *
+ * @param session
+ * the {@link ClientSession}
+ * @param service
+ * the name of the requesting SSH service name
+ * @param mechanism
+ * the OID of the mechanism used
+ */
+ default void signalAuthenticationAttempt(ClientSession session,
+ String service, String mechanism) {
+ // nothing
+ }
+
+ /**
+ * Called when there are no more mechanisms to try.
+ *
+ * @param session
+ * the {@link ClientSession}
+ * @param service
+ * the name of the requesting SSH service name
+ */
+ default void signalAuthenticationExhausted(ClientSession session,
+ String service) {
+ // nothing
+ }
+
+ /**
+ * Called when authentication was succeessful.
+ *
+ * @param session
+ * the {@link ClientSession}
+ * @param service
+ * the name of the requesting SSH service name
+ * @param mechanism
+ * the OID of the mechanism used
+ */
+ default void signalAuthenticationSuccess(ClientSession session,
+ String service, String mechanism) {
+ // nothing
+ }
+
+ /**
+ * Called when the authentication was not successful.
+ *
+ * @param session
+ * the {@link ClientSession}
+ * @param service
+ * the name of the requesting SSH service name
+ * @param mechanism
+ * the OID of the mechanism used
+ * @param partial
+ * {@code true} if authentication was partially successful,
+ * meaning one continues with additional authentication methods
+ * given by {@code serverMethods}
+ * @param serverMethods
+ * the {@link List} of authentication methods that can continue
+ */
+ default void signalAuthenticationFailure(ClientSession session,
+ String service, String mechanism, boolean partial,
+ List<String> serverMethods) {
+ // nothing
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java
index ff8caaacc0..33c3c608f6 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java
@@ -1,5 +1,5 @@
/*
- * 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
@@ -11,13 +11,11 @@ package org.eclipse.jgit.internal.transport.sshd;
import static org.apache.sshd.core.CoreModuleProperties.PASSWORD_PROMPTS;
-import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.auth.password.UserAuthPassword;
import org.apache.sshd.client.session.ClientSession;
/**
- * A password authentication handler that uses the {@link JGitUserInteraction}
- * to ask the user for the password. It also respects the
+ * A password authentication handler that respects the
* {@code NumberOfPasswordPrompts} ssh config.
*/
public class JGitPasswordAuthentication extends UserAuthPassword {
@@ -35,30 +33,11 @@ public class JGitPasswordAuthentication extends UserAuthPassword {
}
@Override
- protected boolean sendAuthDataRequest(ClientSession session, String service)
- throws Exception {
+ protected String resolveAttemptedPassword(ClientSession session,
+ String service) throws Exception {
if (++attempts > maxAttempts) {
- return false;
+ return null;
}
- UserInteraction interaction = session.getUserInteraction();
- if (!interaction.isInteractionAllowed(session)) {
- return false;
- }
- String password = getPassword(session, interaction);
- if (password == null) {
- throw new AuthenticationCanceledException();
- }
- // sendPassword takes a buffer as first argument, but actually doesn't
- // use it and creates its own buffer...
- sendPassword(null, session, password, password);
- return true;
- }
-
- private String getPassword(ClientSession session,
- UserInteraction interaction) {
- String[] results = interaction.interactive(session, null, null, "", //$NON-NLS-1$
- new String[] { SshdText.get().passwordPrompt },
- new boolean[] { false });
- return (results == null || results.length == 0) ? null : results[0];
+ return super.resolveAttemptedPassword(session, service);
}
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
index 71e8e61585..72f0bdb6ee 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2021 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
@@ -87,6 +87,11 @@ public class JGitSshClient extends SshClient {
public static final AttributeKey<String> PREFERRED_AUTHENTICATIONS = new AttributeKey<>();
/**
+ * An attribute key for the home directory.
+ */
+ public static final AttributeKey<Path> HOME_DIRECTORY = new AttributeKey<>();
+
+ /**
* An attribute key for storing an alternate local address to connect to if
* a local forward from a ProxyJump ssh config is present. If set,
* {@link #connect(HostConfigEntry, AttributeRepository, SocketAddress)}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java
index c51a75bc6f..2a725ea16a 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitUserInteraction.java
@@ -1,5 +1,5 @@
/*
- * 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
@@ -120,15 +120,16 @@ public class JGitUserInteraction implements UserInteraction {
return null;
}).filter(s -> s != null).toArray(String[]::new);
}
- // TODO What to throw to abort the connection/authentication process?
- // In UserAuthKeyboardInteractive.getUserResponses() it's clear that
- // returning null is valid and signifies "an error"; we'll try the
- // next authentication method. But if the user explicitly canceled,
- // then we don't want to try the next methods...
- //
- // Probably not a serious issue with the typical order of public-key,
- // keyboard-interactive, password.
- return null;
+ throw new AuthenticationCanceledException();
+ }
+
+ @Override
+ public String resolveAuthPasswordAttempt(ClientSession session)
+ throws Exception {
+ String[] results = interactive(session, null, null, "", //$NON-NLS-1$
+ new String[] { SshdText.get().passwordPrompt },
+ new boolean[] { false });
+ return (results == null || results.length == 0) ? null : results[0];
}
@Override
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 19ad85c83d..39332d9fca 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2021 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
@@ -29,6 +29,23 @@ public final class SshdText extends TranslationBundle {
// @formatter:off
/***/ public String authenticationCanceled;
/***/ public String authenticationOnClosedSession;
+ /***/ public String authGssApiAttempt;
+ /***/ public String authGssApiExhausted;
+ /***/ public String authGssApiFailure;
+ /***/ public String authGssApiNotTried;
+ /***/ public String authGssApiPartialSuccess;
+ /***/ public String authPasswordAttempt;
+ /***/ public String authPasswordChangeAttempt;
+ /***/ public String authPasswordExhausted;
+ /***/ public String authPasswordFailure;
+ /***/ public String authPasswordNotTried;
+ /***/ public String authPasswordPartialSuccess;
+ /***/ public String authPubkeyAttempt;
+ /***/ public String authPubkeyAttemptAgent;
+ /***/ public String authPubkeyExhausted;
+ /***/ public String authPubkeyFailure;
+ /***/ public String authPubkeyNoKeys;
+ /***/ public String authPubkeyPartialSuccess;
/***/ public String closeListenerFailed;
/***/ public String cannotReadPublicKey;
/***/ public String configInvalidPath;
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 b742f5ea42..b94ccc6d4f 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2021 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
@@ -52,6 +52,8 @@ 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.AuthenticationCanceledException;
+import org.eclipse.jgit.internal.transport.sshd.AuthenticationLogger;
import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
import org.eclipse.jgit.internal.transport.sshd.SshdText;
import org.eclipse.jgit.transport.FtpChannel;
@@ -119,6 +121,7 @@ public class SshdSession implements RemoteSession2 {
ClientSession resultSession = null;
ClientSession proxySession = null;
PortForwardingTracker portForward = null;
+ AuthenticationLogger authLog = null;
try {
if (!hops.isEmpty()) {
URIish hop = hops.remove(0);
@@ -165,6 +168,7 @@ public class SshdSession implements RemoteSession2 {
resultSession.addCloseFutureListener(listener);
}
// Authentication timeout is by default 2 minutes.
+ authLog = new AuthenticationLogger(resultSession);
resultSession.auth().verify(resultSession.getAuthTimeout());
return resultSession;
} catch (IOException e) {
@@ -173,15 +177,32 @@ public class SshdSession implements RemoteSession2 {
close(resultSession, e);
if (e instanceof SshException && ((SshException) e)
.getDisconnectCode() == SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) {
- // Ensure the user gets to know on which URI the authentication
- // was denied.
+ String message = format(SshdText.get().loginDenied, host,
+ Integer.toString(port));
throw new TransportException(target,
- format(SshdText.get().loginDenied, host,
- Integer.toString(port)),
- e);
+ withAuthLog(message, authLog), e);
+ } else if (e instanceof SshException && e
+ .getCause() instanceof AuthenticationCanceledException) {
+ String message = e.getCause().getMessage();
+ throw new TransportException(target,
+ withAuthLog(message, authLog), e.getCause());
}
throw e;
+ } finally {
+ if (authLog != null) {
+ authLog.clear();
+ }
+ }
+ }
+
+ private String withAuthLog(String message, AuthenticationLogger authLog) {
+ if (authLog != null) {
+ String log = String.join(System.lineSeparator(), authLog.getLog());
+ if (!log.isEmpty()) {
+ return message + System.lineSeparator() + log;
+ }
}
+ return message;
}
private ClientSession connect(HostConfigEntry config,
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
index 58cf8e1ddd..c792c1889c 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2021 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
@@ -13,6 +13,7 @@ import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.security.KeyPair;
import java.time.Duration;
@@ -34,7 +35,6 @@ import org.apache.sshd.client.auth.UserAuthFactory;
import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.SshException;
import org.apache.sshd.common.compression.BuiltinCompressions;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.config.keys.loader.openssh.kdf.BCryptKdfOptions;
@@ -44,7 +44,6 @@ import org.apache.sshd.common.signature.Signature;
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.AuthenticationCanceledException;
import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider;
import org.eclipse.jgit.internal.transport.sshd.GssApiWithMicAuthFactory;
import org.eclipse.jgit.internal.transport.sshd.JGitPasswordAuthFactory;
@@ -243,6 +242,12 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable {
JGitSshClient.PREFERRED_AUTHENTICATIONS,
defaultAuths);
}
+ try {
+ jgitClient.setAttribute(JGitSshClient.HOME_DIRECTORY,
+ home.getAbsoluteFile().toPath());
+ } catch (SecurityException | InvalidPathException e) {
+ // Ignore
+ }
// Other things?
return client;
});
@@ -255,13 +260,7 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable {
if (e instanceof TransportException) {
throw (TransportException) e;
}
- Throwable cause = e;
- if (e instanceof SshException && e
- .getCause() instanceof AuthenticationCanceledException) {
- // Results in a nicer error message
- cause = e.getCause();
- }
- throw new TransportException(uri, cause.getMessage(), cause);
+ throw new TransportException(uri, e.getMessage(), e);
}
}
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 4a08940c83..f48b926402 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-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ssh.jsch.test
Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.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.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.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit.ssh;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.ssh.jsch;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.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 ca1e742344..9a3a847951 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 332d981cf9..4238239b5b 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-ManifestVersion: 2
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.1.1,6.2.0)"
+Fragment-Host: org.eclipse.jgit;bundle-version="[6.2.0,6.3.0)"
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="6.1.1"
+Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="6.2.0"
Import-Package: com.jcraft.jsch;version="[0.1.37,0.2.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.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.0,6.3.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 b56bb7c6e0..edb6b195fd 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.ssh.jsch - Sources
Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.jsch/pom.xml b/org.eclipse.jgit.ssh.jsch/pom.xml
index 3b6d66c68c..1ff971f835 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ssh.jsch</artifactId>
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 581395d90c..85d93a95d6 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.test
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -16,61 +16,61 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
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.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.eclipse.jgit.annotations;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.archive;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.attributes;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.awtui;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.blame;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.diff;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.dircache;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.events;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.fnmatch;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.gitrepo;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.hooks;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.ignore;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.ignore.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.fsck;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.io;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.connectivity;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.junit.time;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lfs;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.logging;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.merge;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.notes;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.patch;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.pgm;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revplot;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.storage.pack;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.submodule;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util.sha1;version="[6.2.0,6.3.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 6b66919894..0d1e5458fc 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
index 6479d157eb..0884d72235 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
@@ -96,6 +96,53 @@ public class FetchCommandTest extends RepositoryTestCase {
}
@Test
+ public void testFetchSimpleNegativeRefSpec() throws Exception {
+ remoteGit.commit().setMessage("commit").call();
+
+ FetchResult res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/heads/master:refs/heads/test",
+ "^:refs/heads/test")
+ .call();
+ assertNull(res.getTrackingRefUpdate("refs/heads/test"));
+
+ res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/heads/master:refs/heads/test",
+ "^refs/heads/master")
+ .call();
+ assertNull(res.getTrackingRefUpdate("refs/heads/test"));
+ }
+
+ @Test
+ public void negativeRefSpecFilterBySource() throws Exception {
+ remoteGit.commit().setMessage("commit").call();
+ remoteGit.branchCreate().setName("test").call();
+ remoteGit.commit().setMessage("commit1").call();
+ remoteGit.branchCreate().setName("dev").call();
+
+ FetchResult res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/*:refs/origins/*", "^refs/*/test")
+ .call();
+ assertNotNull(res.getTrackingRefUpdate("refs/origins/heads/master"));
+ assertNull(res.getTrackingRefUpdate("refs/origins/heads/test"));
+ assertNotNull(res.getTrackingRefUpdate("refs/origins/heads/dev"));
+ }
+
+ @Test
+ public void negativeRefSpecFilterByDestination() throws Exception {
+ remoteGit.commit().setMessage("commit").call();
+ remoteGit.branchCreate().setName("meta").call();
+ remoteGit.commit().setMessage("commit1").call();
+ remoteGit.branchCreate().setName("data").call();
+
+ FetchResult res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/*:refs/secret/*", "^:refs/secret/*/meta")
+ .call();
+ assertNotNull(res.getTrackingRefUpdate("refs/secret/heads/master"));
+ assertNull(res.getTrackingRefUpdate("refs/secret/heads/meta"));
+ assertNotNull(res.getTrackingRefUpdate("refs/secret/heads/data"));
+ }
+
+ @Test
public void fetchAddsBranches() throws Exception {
final String branch1 = "b1";
final String branch2 = "b2";
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java
index 12ec2aae57..05af175cfa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java
@@ -21,6 +21,8 @@ import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.util.SystemReader;
import org.junit.Test;
public class LsRemoteCommandTest extends RepositoryTestCase {
@@ -107,6 +109,20 @@ public class LsRemoteCommandTest extends RepositoryTestCase {
}
@Test
+ public void testLsRemoteWithoutLocalRepositoryUrlInsteadOf()
+ throws Exception {
+ String uri = fileUri();
+ StoredConfig userConfig = SystemReader.getInstance().getUserConfig();
+ userConfig.load();
+ userConfig.setString("url", uri, "insteadOf", "file:///foo");
+ userConfig.save();
+ Collection<Ref> refs = Git.lsRemoteRepository().setRemote("file:///foo")
+ .setHeads(true).call();
+ assertNotNull(refs);
+ assertEquals(2, refs.size());
+ }
+
+ @Test
public void testLsRemoteWithSymRefs() throws Exception {
File directory = createTempDirectory("testRepository");
CloneCommand command = Git.cloneRepository();
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 64475f5d50..917b6c3297 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
@@ -36,6 +36,7 @@ import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.Sets;
+import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
@@ -2018,6 +2019,73 @@ public class MergeCommandTest extends RepositoryTestCase {
}
}
+ @Test
+ public void testMergeConflictWithMessageAndCommentChar() throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("side").call();
+
+ checkoutBranch("refs/heads/master");
+
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
+
+ StoredConfig config = db.getConfig();
+ config.setString("core", null, "commentChar", "^");
+
+ Ref sideBranch = db.exactRef("refs/heads/side");
+
+ git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+ .setMessage("user message").call();
+
+ assertEquals("user message\n\n^ Conflicts:\n^\ta\n",
+ db.readMergeCommitMsg());
+ }
+ }
+
+ @Test
+ public void testMergeConflictWithMessageAndCommentCharAuto()
+ throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("side").call();
+
+ checkoutBranch("refs/heads/master");
+
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
+
+ StoredConfig config = db.getConfig();
+ config.setString("core", null, "commentChar", "auto");
+
+ Ref sideBranch = db.exactRef("refs/heads/side");
+
+ git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+ .setMessage("#user message").call();
+
+ assertEquals("#user message\n\n; Conflicts:\n;\ta\n",
+ db.readMergeCommitMsg());
+ }
+ }
+
private static void setExecutable(Git git, String path, boolean executable) {
FS.DETECTED.setExecute(
new File(git.getRepository().getWorkTree(), path), executable);
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 c64ff0b1c3..d574e45f6f 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
@@ -30,6 +30,7 @@ import java.util.List;
import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;
+import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler2;
import org.eclipse.jgit.api.RebaseCommand.Operation;
import org.eclipse.jgit.api.RebaseResult.Status;
import org.eclipse.jgit.api.errors.InvalidRebaseStepException;
@@ -46,6 +47,7 @@ import org.eclipse.jgit.events.ChangeRecorder;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -56,6 +58,7 @@ import org.eclipse.jgit.lib.RebaseTodoLine.Action;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.RepositoryState;
+import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
@@ -3410,6 +3413,99 @@ public class RebaseCommandTest extends RepositoryTestCase {
}
+ @Test
+ public void testInteractiveRebaseSquashFixupSequence() throws Exception {
+ // create file1, add and commit
+ writeTrashFile(FILE1, "file1");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage("commit1").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage("commit2").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1 a second time");
+ git.add().addFilepattern(FILE1).call();
+ // Make it difficult; use git standard comment characters in the commit
+ // messages
+ git.commit().setMessage("#commit3").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1 a third time");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage("@commit4").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1 a fourth time");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage(";commit5").call();
+
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("core", null, "commentChar", "auto");
+ // With "auto", we should end up with '@' being used as comment
+ // character (commit4 is skipped, so it should not advance the
+ // character).
+ RebaseResult result = git.rebase().setUpstream("HEAD~4")
+ .runInteractively(new InteractiveHandler2() {
+
+ @Override
+ public void prepareSteps(List<RebaseTodoLine> steps) {
+ try {
+ steps.get(0).setAction(Action.PICK);
+ steps.get(1).setAction(Action.SQUASH);
+ steps.get(2).setAction(Action.FIXUP);
+ steps.get(3).setAction(Action.SQUASH);
+ } catch (IllegalTodoFileModification e) {
+ fail("unexpected exception: " + e);
+ }
+ }
+
+ @Override
+ public String modifyCommitMessage(String commit) {
+ fail("should not be called");
+ return commit;
+ }
+
+ @Override
+ public ModifyResult editCommitMessage(String message,
+ CleanupMode mode, char commentChar) {
+ assertEquals('@', commentChar);
+ assertEquals("@ This is a combination of 4 commits.\n"
+ + "@ The first commit's message is:\n"
+ + "commit2\n"
+ + "@ This is the 2nd commit message:\n"
+ + "#commit3\n"
+ + "@ The 3rd commit message will be skipped:\n"
+ + "@ @commit4\n"
+ + "@ This is the 4th commit message:\n"
+ + ";commit5", message);
+ return new ModifyResult() {
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public CleanupMode getCleanupMode() {
+ return mode;
+ }
+
+ @Override
+ public boolean shouldAddChangeId() {
+ return false;
+ }
+ };
+ }
+ }).call();
+ assertEquals(Status.OK, result.getStatus());
+ Iterator<RevCommit> logIterator = git.log().all().call().iterator();
+ String actualCommitMsg = logIterator.next().getFullMessage();
+ assertEquals("commit2\n#commit3\n;commit5", actualCommitMsg);
+ }
+
private File getTodoFile() {
File todoFile = new File(db.getDirectory(), GIT_REBASE_TODO);
return todoFile;
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
index c9ebec7638..f69a1794ef 100644
--- 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
@@ -10,21 +10,36 @@
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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.internal.BooleanTriState;
import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS.ExecutionResult;
import org.junit.Test;
/**
@@ -32,20 +47,119 @@ import org.junit.Test;
*/
public class ExternalDiffToolTest extends ExternalToolTestCase {
+ @Test(expected = ToolException.class)
+ public void testUserToolWithError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 1;
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeCompare(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeCompare(toolName);
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test
+ public void testUserDefinedTool() throws Exception {
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ DiffTools manager = new DiffTools(db);
+
+ Map<String, ExternalDiffTool> tools = manager.getUserDefinedTools();
+ ExternalDiffTool externalTool = tools.get(customToolName);
+ boolean trustExitCode = true;
+ manager.compare(local, remote, externalTool, trustExitCode);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testUserDefinedToolWithPrompt() throws Exception {
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ DiffTools manager = new DiffTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.compare(local, remote, Optional.of(customToolName),
+ BooleanTriState.TRUE, false, BooleanTriState.TRUE,
+ promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+
+ List<String> actualToolPrompts = promptHandler.toolPrompts;
+ List<String> expectedToolPrompts = Arrays.asList("customTool");
+ assertEquals("Expected a user prompt for custom tool call",
+ expectedToolPrompts, actualToolPrompts);
+
+ assertEquals("Expected to no informing about missing tools",
+ Collections.EMPTY_LIST, noToolHandler.missingTools);
+ }
+
@Test
- public void testToolNames() {
+ public void testUserDefinedToolWithCancelledPrompt() throws Exception {
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
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);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.compare(local, remote,
+ Optional.of(customToolName), BooleanTriState.TRUE, false,
+ BooleanTriState.TRUE, promptHandler, noToolHandler);
+ assertFalse("Expected no result if user cancels the operation",
+ result.isPresent());
}
@Test
public void testAllTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, "echo");
+
DiffTools manager = new DiffTools(db);
- Set<String> actualToolNames = manager.getAvailableTools().keySet();
+ Set<String> actualToolNames = manager.getAllToolNames();
Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolName);
CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
for (CommandLineDiffTool defaultTool : defaultTools) {
String toolName = defaultTool.name();
@@ -86,11 +200,11 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
CONFIG_KEY_PATH, "/usr/bin/echo");
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
- CONFIG_KEY_PROMPT, "--no-prompt");
+ CONFIG_KEY_PROMPT, String.valueOf(false));
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
- CONFIG_KEY_GUITOOL, "--no-gui");
+ CONFIG_KEY_GUITOOL, String.valueOf(false));
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
- CONFIG_KEY_TRUST_EXIT_CODE, "--no-trust-exit-code");
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(false));
DiffTools manager = new DiffTools(db);
Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
Set<String> expectedToolNames = new LinkedHashSet<>();
@@ -100,59 +214,240 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
}
@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);
- }
+ public void testCompare() throws ToolException {
+ String toolName = "customTool";
- @Test
- public void testCompare() {
- DiffTools manager = new DiffTools(db);
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
- String newPath = "";
- String oldPath = "";
- String newId = "";
- String oldId = "";
- String toolName = "";
- BooleanTriState prompt = BooleanTriState.UNSET;
- BooleanTriState gui = BooleanTriState.UNSET;
- BooleanTriState trustExitCode = BooleanTriState.UNSET;
+ String command = getEchoCommand();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ Optional<ExecutionResult> result = invokeCompare(toolName);
+ assertTrue("Expected external diff tool result to be available",
+ result.isPresent());
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);
+ expectedCompareResult, result.get().getRc());
}
@Test
public void testDefaultTool() throws Exception {
+ String toolName = "customTool";
+ String guiToolName = "customGuiTool";
+
FileBasedConfig config = db.getConfig();
// the default diff tool is configured without a subsection
String subsection = null;
- config.setString("diff", subsection, "tool", "customTool");
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
DiffTools manager = new DiffTools(db);
- BooleanTriState gui = BooleanTriState.UNSET;
+ boolean gui = false;
String defaultToolName = manager.getDefaultToolName(gui);
assertEquals(
"Expected configured difftool to be the default external diff tool",
- "my_default_toolname", defaultToolName);
+ toolName, defaultToolName);
- gui = BooleanTriState.TRUE;
+ gui = true;
String defaultGuiToolName = manager.getDefaultToolName(gui);
assertEquals(
- "Expected configured difftool to be the default external diff tool",
- "my_gui_tool", defaultGuiToolName);
+ "Expected default gui difftool to be the default tool if no gui tool is set",
+ toolName, defaultGuiToolName);
- config.setString("diff", subsection, "guitool", "customGuiTool");
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_GUITOOL,
+ guiToolName);
manager = new DiffTools(db);
defaultGuiToolName = manager.getDefaultToolName(gui);
assertEquals(
"Expected configured difftool to be the default external diff guitool",
- "my_gui_tool", defaultGuiToolName);
+ guiToolName, defaultGuiToolName);
+ }
+
+ @Test
+ public void testOverridePreDefinedToolPath() {
+ String newToolPath = "/tmp/path/";
+
+ CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
+ assertTrue("Expected to find pre-defined external diff tools",
+ defaultTools.length > 0);
+
+ CommandLineDiffTool overridenTool = defaultTools[0];
+ String overridenToolName = overridenTool.name();
+ String overridenToolPath = newToolPath + overridenToolName;
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, overridenToolName,
+ CONFIG_KEY_PATH, overridenToolPath);
+
+ DiffTools manager = new DiffTools(db);
+ Map<String, ExternalDiffTool> availableTools = manager
+ .getPredefinedTools(true);
+ ExternalDiffTool externalDiffTool = availableTools
+ .get(overridenToolName);
+ String actualDiffToolPath = externalDiffTool.getPath();
+ assertEquals(
+ "Expected pre-defined external diff tool to have overriden path",
+ overridenToolPath, actualDiffToolPath);
+ String expectedDiffToolCommand = overridenToolPath + " "
+ + overridenTool.getParameters();
+ String actualDiffToolCommand = externalDiffTool.getCommand();
+ assertEquals(
+ "Expected pre-defined external diff tool to have overriden command",
+ expectedDiffToolCommand, actualDiffToolCommand);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ invokeCompare(toolName);
+ fail("Expected exception to be thrown due to not defined external diff tool");
+ }
+
+ @Test
+ public void testDefaultToolExecutionWithPrompt() throws Exception {
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString("diff", subsection, "tool", "customTool");
+
+ String command = getEchoCommand();
+
+ config.setString("difftool", "customTool", "cmd", command);
+
+ DiffTools manager = new DiffTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.compare(local, remote, Optional.empty(), BooleanTriState.TRUE,
+ false, BooleanTriState.TRUE, promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testNoDefaultToolName() {
+ DiffTools manager = new DiffTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+
+ gui = true;
+ defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+ }
+
+ @Test
+ public void testExternalToolInGitAttributes() throws Exception {
+ String content = "attributes:\n*.txt difftool=customTool";
+ File gitattributes = writeTrashFile(".gitattributes", content);
+ gitattributes.deleteOnExit();
+ try (TestRepository<Repository> testRepository = new TestRepository<>(
+ db)) {
+ FileBasedConfig config = db.getConfig();
+ config.setString("difftool", "customTool", "cmd", "echo");
+ testRepository.git().add().addFilepattern(localFile.getName())
+ .call();
+
+ testRepository.git().add().addFilepattern(".gitattributes").call();
+
+ testRepository.branch("master").commit().message("first commit")
+ .create();
+
+ DiffTools manager = new DiffTools(db);
+ Optional<String> tool = manager
+ .getExternalToolFromAttributes(localFile.getName());
+ assertTrue("Failed to find user defined tool", tool.isPresent());
+ assertEquals("Failed to find user defined tool", "customTool",
+ tool.get());
+ } finally {
+ Files.delete(gitattributes.toPath());
+ }
+ }
+
+ @Test
+ public void testNotExternalToolInGitAttributes() throws Exception {
+ String content = "";
+ File gitattributes = writeTrashFile(".gitattributes", content);
+ gitattributes.deleteOnExit();
+ try (TestRepository<Repository> testRepository = new TestRepository<>(
+ db)) {
+ FileBasedConfig config = db.getConfig();
+ config.setString("difftool", "customTool", "cmd", "echo");
+ testRepository.git().add().addFilepattern(localFile.getName())
+ .call();
+
+ testRepository.git().add().addFilepattern(".gitattributes").call();
+
+ testRepository.branch("master").commit().message("first commit")
+ .create();
+
+ DiffTools manager = new DiffTools(db);
+ Optional<String> tool = manager
+ .getExternalToolFromAttributes(localFile.getName());
+ assertFalse(
+ "Expected no external tool if no default tool is specified in .gitattributes",
+ tool.isPresent());
+ } finally {
+ Files.delete(gitattributes.toPath());
+ }
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullTool() throws Exception {
+ DiffTools manager = new DiffTools(db);
+
+ boolean trustExitCode = true;
+ ExternalDiffTool tool = null;
+ manager.compare(local, remote, tool, trustExitCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullToolWithPrompt() throws Exception {
+ DiffTools manager = new DiffTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<String> tool = null;
+ manager.compare(local, remote, tool, BooleanTriState.TRUE, false,
+ BooleanTriState.TRUE, promptHandler, noToolHandler);
+ }
+
+ private Optional<ExecutionResult> invokeCompare(String toolName)
+ throws ToolException {
+ DiffTools manager = new DiffTools(db);
+
+ BooleanTriState prompt = BooleanTriState.UNSET;
+ boolean gui = false;
+ BooleanTriState trustExitCode = BooleanTriState.TRUE;
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.compare(local, remote,
+ Optional.of(toolName), prompt, gui, trustExitCode,
+ promptHandler, noToolHandler);
+ return result;
+ }
+
+ private String getEchoCommand() {
+ return "(echo \"$LOCAL\" \"$REMOTE\") > "
+ + commandResult.getAbsolutePath();
+ }
+
+ private void assertEchoCommandHasCorrectOutput() throws IOException {
+ List<String> actualLines = Files.readAllLines(commandResult.toPath());
+ String actualContent = String.join(System.lineSeparator(), actualLines);
+ actualLines = Arrays.asList(actualContent.split(" "));
+ List<String> expectedLines = Arrays.asList(localFile.getAbsolutePath(),
+ remoteFile.getAbsolutePath());
+ assertEquals("Dummy test tool called with unexpected arguments",
+ expectedLines, actualLines);
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
new file mode 100644
index 0000000000..94b67b374b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2020-2022, 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_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 static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGETOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.junit.Test;
+
+/**
+ * Testing external merge tools.
+ */
+public class ExternalMergeToolTest extends ExternalToolTestCase {
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 1;
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName,
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(Boolean.TRUE));
+
+ invokeMerge(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeMerge(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test
+ public void testKdiff3() throws Exception {
+ assumePosixPlatform();
+
+ CommandLineMergeTool autoMergingTool = CommandLineMergeTool.kdiff3;
+ assumeMergeToolIsAvailable(autoMergingTool);
+
+ CommandLineMergeTool tool = autoMergingTool;
+ PreDefinedMergeTool externalTool = new PreDefinedMergeTool(tool.name(),
+ tool.getPath(), tool.getParameters(true),
+ tool.getParameters(false),
+ tool.isExitCodeTrustable() ? BooleanTriState.TRUE
+ : BooleanTriState.FALSE);
+
+ MergeTools manager = new MergeTools(db);
+ ExecutionResult result = manager.merge(local, remote, merged, null,
+ null, externalTool);
+ assertEquals("Expected merge tool to succeed", 0, result.getRc());
+
+ List<String> actualLines = Files.readAllLines(mergedFile.toPath());
+ String actualMergeResult = String.join(System.lineSeparator(),
+ actualLines);
+ String expectedMergeResult = DEFAULT_CONTENT;
+ assertEquals(
+ "Failed to merge equal local and remote versions with pre-defined tool: "
+ + tool.getPath(),
+ expectedMergeResult, actualMergeResult);
+ }
+
+ @Test
+ public void testUserDefinedTool() throws Exception {
+ String customToolName = "customTool";
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> tools = manager.getUserDefinedTools();
+ ExternalMergeTool externalTool = tools.get(customToolName);
+ manager.merge(local, remote, merged, base, null, externalTool);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testUserDefinedToolWithPrompt() throws Exception {
+ String customToolName = "customTool";
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.merge(local, remote, merged, base, null,
+ Optional.of(customToolName), BooleanTriState.TRUE, false,
+ promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+
+ List<String> actualToolPrompts = promptHandler.toolPrompts;
+ List<String> expectedToolPrompts = Arrays.asList("customTool");
+ assertEquals("Expected a user prompt for custom tool call",
+ expectedToolPrompts, actualToolPrompts);
+
+ assertEquals("Expected to no informing about missing tools",
+ Collections.EMPTY_LIST, noToolHandler.missingTools);
+ }
+
+ @Test
+ public void testUserDefinedToolWithCancelledPrompt() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.merge(local, remote, merged,
+ base, null, Optional.empty(), BooleanTriState.TRUE, false,
+ promptHandler, noToolHandler);
+ assertFalse("Expected no result if user cancels the operation",
+ result.isPresent());
+ }
+
+ @Test
+ public void testAllTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, "echo");
+
+ MergeTools manager = new MergeTools(db);
+ Set<String> actualToolNames = manager.getAllToolNames();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolName);
+ CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values();
+ for (CommandLineMergeTool defaultTool : defaultTools) {
+ String toolName = defaultTool.name();
+ expectedToolNames.add(toolName);
+ }
+ assertEquals("Incorrect set of external merge tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testOverridePredefinedToolPath() {
+ String toolName = CommandLineMergeTool.guiffy.name();
+ String customToolPath = "/usr/bin/echo";
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ "echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_PATH,
+ customToolPath);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> tools = manager.getUserDefinedTools();
+ ExternalMergeTool mergeTool = tools.get(toolName);
+ assertNotNull("Expected tool \"" + toolName + "\" to be user defined",
+ mergeTool);
+
+ String toolPath = mergeTool.getPath();
+ assertEquals("Expected external merge tool to have an overriden path",
+ customToolPath, toolPath);
+ }
+
+ @Test
+ public void testUserDefinedTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolname = "customTool";
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_CMD, "echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_PATH, "/usr/bin/echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_PROMPT, String.valueOf(false));
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_GUITOOL, String.valueOf(false));
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(false));
+ MergeTools manager = new MergeTools(db);
+ Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolname);
+ assertEquals("Incorrect set of external merge tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testCompare() throws ToolException {
+ String toolName = "customTool";
+
+ FileBasedConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ String command = getEchoCommand();
+
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ Optional<ExecutionResult> result = invokeMerge(toolName);
+ assertTrue("Expected external merge tool result to be available",
+ result.isPresent());
+ int expectedCompareResult = 0;
+ assertEquals("Incorrect compare result for external merge tool",
+ expectedCompareResult, result.get().getRc());
+ }
+
+ @Test
+ public void testDefaultTool() throws Exception {
+ String toolName = "customTool";
+ String guiToolName = "customGuiTool";
+
+ FileBasedConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ MergeTools manager = new MergeTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured mergetool to be the default external merge tool",
+ toolName, defaultToolName);
+
+ gui = true;
+ String defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected default mergetool to not be set",
+ defaultGuiToolName);
+
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_GUITOOL,
+ guiToolName);
+ manager = new MergeTools(db);
+ defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured mergetool to be the default external merge guitool",
+ guiToolName, defaultGuiToolName);
+ }
+
+ @Test
+ public void testOverridePreDefinedToolPath() {
+ String newToolPath = "/tmp/path/";
+
+ CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values();
+ assertTrue("Expected to find pre-defined external merge tools",
+ defaultTools.length > 0);
+
+ CommandLineMergeTool overridenTool = defaultTools[0];
+ String overridenToolName = overridenTool.name();
+ String overridenToolPath = newToolPath + overridenToolName;
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, overridenToolName,
+ CONFIG_KEY_PATH, overridenToolPath);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> availableTools = manager
+ .getPredefinedTools(true);
+ ExternalMergeTool externalMergeTool = availableTools
+ .get(overridenToolName);
+ String actualMergeToolPath = externalMergeTool.getPath();
+ assertEquals(
+ "Expected pre-defined external merge tool to have overriden path",
+ overridenToolPath, actualMergeToolPath);
+ boolean withBase = true;
+ String expectedMergeToolCommand = overridenToolPath + " "
+ + overridenTool.getParameters(withBase);
+ String actualMergeToolCommand = externalMergeTool.getCommand();
+ assertEquals(
+ "Expected pre-defined external merge tool to have overriden command",
+ expectedMergeToolCommand, actualMergeToolCommand);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ invokeMerge(toolName);
+ fail("Expected exception to be thrown due to not defined external merge tool");
+ }
+
+ @Test
+ public void testDefaultToolExecutionWithPrompt() throws Exception {
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString("merge", subsection, "tool", "customTool");
+
+ String command = getEchoCommand();
+
+ config.setString("mergetool", "customTool", "cmd", command);
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.merge(local, remote, merged, base, null, Optional.empty(),
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testNoDefaultToolName() {
+ MergeTools manager = new MergeTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+
+ gui = true;
+ defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullTool() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = null;
+ MissingToolHandler noToolHandler = null;
+
+ Optional<String> tool = null;
+
+ manager.merge(local, remote, merged, base, null, tool,
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullToolWithPrompt() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<String> tool = null;
+
+ manager.merge(local, remote, merged, base, null, tool,
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+ }
+
+ private Optional<ExecutionResult> invokeMerge(String toolName)
+ throws ToolException {
+ BooleanTriState prompt = BooleanTriState.UNSET;
+ boolean gui = false;
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.merge(local, remote, merged,
+ base, null, Optional.of(toolName), prompt, gui, promptHandler,
+ noToolHandler);
+ return result;
+ }
+
+ private void assumeMergeToolIsAvailable(
+ CommandLineMergeTool autoMergingTool) {
+ boolean isAvailable = ExternalToolUtils.isToolAvailable(db.getFS(),
+ db.getDirectory(), db.getWorkTree(), autoMergingTool.getPath());
+ assumeTrue("Assuming external tool is available: "
+ + autoMergingTool.name(), isAvailable);
+ }
+
+ private String getEchoCommand() {
+ return "(echo $LOCAL $REMOTE $MERGED $BASE) > "
+ + commandResult.getAbsolutePath();
+ }
+
+ private void assertEchoCommandHasCorrectOutput() throws IOException {
+ List<String> actualLines = Files.readAllLines(commandResult.toPath());
+ String actualContent = String.join(System.lineSeparator(), actualLines);
+ actualLines = Arrays.asList(actualContent.split(" "));
+ List<String> expectedLines = Arrays.asList(localFile.getAbsolutePath(),
+ remoteFile.getAbsolutePath(), mergedFile.getAbsolutePath(),
+ baseFile.getAbsolutePath());
+ assertEquals("Dummy test tool called with unexpected arguments",
+ expectedLines, actualLines);
+ }
+}
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
index 0cc12978a8..7a6ff46578 100644
--- 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
@@ -11,6 +11,8 @@ package org.eclipse.jgit.internal.diffmergetool;
import java.io.File;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.util.FS;
@@ -36,6 +38,14 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
protected File commandResult;
+ protected FileElement local;
+
+ protected FileElement remote;
+
+ protected FileElement merged;
+
+ protected FileElement base;
+
@Before
@Override
public void setUp() throws Exception {
@@ -51,6 +61,15 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
baseFile.deleteOnExit();
commandResult = writeTrashFile("commandResult.txt", "");
commandResult.deleteOnExit();
+
+ local = new FileElement(localFile.getAbsolutePath(),
+ FileElement.Type.LOCAL);
+ remote = new FileElement(remoteFile.getAbsolutePath(),
+ FileElement.Type.REMOTE);
+ merged = new FileElement(mergedFile.getAbsolutePath(),
+ FileElement.Type.MERGED);
+ base = new FileElement(baseFile.getAbsolutePath(),
+ FileElement.Type.BASE);
}
@After
@@ -71,4 +90,39 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
"This test can run only in Linux tests",
FS.DETECTED instanceof FS_POSIX);
}
+
+ protected static class PromptHandler implements PromptContinueHandler {
+
+ private final boolean promptResult;
+
+ final List<String> toolPrompts = new ArrayList<>();
+
+ private PromptHandler(boolean promptResult) {
+ this.promptResult = promptResult;
+ }
+
+ static PromptHandler acceptPrompt() {
+ return new PromptHandler(true);
+ }
+
+ static PromptHandler cancelPrompt() {
+ return new PromptHandler(false);
+ }
+
+ @Override
+ public boolean prompt(String toolName) {
+ toolPrompts.add(toolName);
+ return promptResult;
+ }
+ }
+
+ protected static class MissingToolHandler implements InformNoToolHandler {
+
+ final List<String> missingTools = new ArrayList<>();
+
+ @Override
+ public void inform(List<String> toolNames) {
+ missingTools.addAll(toolNames);
+ }
+ }
}
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
index d95d7814e4..7066f9d422 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
@@ -11,7 +11,10 @@
package org.eclipse.jgit.lib;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
@@ -169,6 +172,82 @@ public class CommitConfigTest {
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
}
+ @Test
+ public void testCommentCharDefault() throws Exception {
+ CommitConfig cfg = parse("");
+ assertEquals('#', cfg.getCommentChar());
+ assertFalse(cfg.isAutoCommentChar());
+ }
+
+ @Test
+ public void testCommentCharAuto() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = auto\n");
+ assertEquals('#', cfg.getCommentChar());
+ assertTrue(cfg.isAutoCommentChar());
+ }
+
+ @Test
+ public void testCommentCharEmpty() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar =\n");
+ assertEquals('#', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testCommentCharInvalid() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = \" \"\n");
+ assertEquals('#', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testCommentCharNonAscii() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = ö\n");
+ assertEquals('#', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testCommentChar() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = _\n");
+ assertEquals('_', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testDetermineCommentChar() throws Exception {
+ String text = "A commit message\n\nBody\n";
+ assertEquals('#', CommitConfig.determineCommentChar(text));
+ }
+
+ @Test
+ public void testDetermineCommentChar2() throws Exception {
+ String text = "A commit message\n\nBody\n\n# Conflicts:\n#\tfoo.txt\n";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertNotEquals('#', ch);
+ assertTrue(ch > ' ' && ch < 127);
+ }
+
+ @Test
+ public void testDetermineCommentChar3() throws Exception {
+ String text = "A commit message\n\n;Body\n\n# Conflicts:\n#\tfoo.txt\n";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertNotEquals('#', ch);
+ assertNotEquals(';', ch);
+ assertTrue(ch > ' ' && ch < 127);
+ }
+
+ @Test
+ public void testDetermineCommentChar4() throws Exception {
+ String text = "A commit message\n\nBody\n\n # Conflicts:\n\t #\tfoo.txt\n";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertNotEquals('#', ch);
+ assertTrue(ch > ' ' && ch < 127);
+ }
+
+ @Test
+ public void testDetermineCommentChar5() throws Exception {
+ String text = "A commit message\n\nBody\n\n#a\n;b\n@c\n!d\n$\n%\n^\n&\n|\n:";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertEquals(0, ch);
+ }
+
private static CommitConfig parse(String content)
throws ConfigInvalidException {
Config c = new Config();
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 b56308cb72..ef0817adb8 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
@@ -443,6 +443,26 @@ public class RefSpecTest {
a.setDestination("refs/remotes/origin/*/*");
}
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidNegativeAndForce() {
+ assertNotNull(new RefSpec("^+refs/heads/master"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidForceAndNegative() {
+ assertNotNull(new RefSpec("+^refs/heads/master"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidNegativeNoSrcDest() {
+ assertNotNull(new RefSpec("^"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidNegativeBothSrcDest() {
+ assertNotNull(new RefSpec("^refs/heads/*:refs/heads/*"));
+ }
+
@Test
public void sourceOnlywithWildcard() {
RefSpec a = new RefSpec("refs/heads/*",
@@ -480,4 +500,32 @@ public class RefSpecTest {
assertTrue(a.isMatching());
assertTrue(a.isForceUpdate());
}
+
+ @Test
+ public void negativeRefSpecWithDest() {
+ RefSpec a = new RefSpec("^:refs/readonly/*");
+ assertTrue(a.isNegative());
+ assertNull(a.getSource());
+ assertEquals(a.getDestination(), "refs/readonly/*");
+ }
+
+ // Because of some of the API's existing behavior, without a colon at the
+ // end of the refspec, dest will be null.
+ @Test
+ public void negativeRefSpecWithSrcAndNullDest() {
+ RefSpec a = new RefSpec("^refs/testdata/*");
+ assertTrue(a.isNegative());
+ assertNull(a.getDestination());
+ assertEquals(a.getSource(), "refs/testdata/*");
+ }
+
+ // Because of some of the API's existing behavior, with a colon at the end
+ // of the refspec, dest will be empty.
+ @Test
+ public void negativeRefSpecWithSrcAndEmptyDest() {
+ RefSpec a = new RefSpec("^refs/testdata/*:");
+ assertTrue(a.isNegative());
+ assertTrue(a.getDestination().isEmpty());
+ assertEquals(a.getSource(), "refs/testdata/*");
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java
new file mode 100644
index 0000000000..7ac83195fb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SideBandInputStreamTest {
+
+ private StringWriter messages;
+
+ private SideBandInputStream sideband;
+
+ @Before
+ public void setup() {
+ messages = new StringWriter();
+ }
+
+ @Test
+ public void progressSingleCR() throws IOException {
+ init(packet("message\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message\r", messages.toString());
+ }
+
+ @Test
+ public void progressSingleLF() throws IOException {
+ init(packet("message\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message\n", messages.toString());
+ }
+
+ @Test
+ public void progressSingleCRLF() throws IOException {
+ init(packet("message\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressMultiCR() throws IOException {
+ init(packet("message 0%\rmessage 100%\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\rmessage 100%\r", messages.toString());
+ }
+
+ @Test
+ public void progressMultiLF() throws IOException {
+ init(packet("message 0%\nmessage 100%\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressMultiCRLF() throws IOException {
+ init(packet("message 0%\r\nmessage 100%\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r\nmessage 100%\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartial() throws IOException {
+ init(packet("message"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialTwoCR() throws IOException {
+ init(packet("message") + packet("message\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessage\r", messages.toString());
+ }
+
+ @Test
+ public void progressPartialTwoLF() throws IOException {
+ init(packet("message") + packet("message\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessage\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialTwoCRLF() throws IOException {
+ init(packet("message") + packet("message\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessage\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialThreeCR() throws IOException {
+ init(packet("message") + packet("message") + packet("message\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessagemessage\r", messages.toString());
+ }
+
+ @Test
+ public void progressPartialThreeLF() throws IOException {
+ init(packet("message") + packet("message") + packet("message\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessagemessage\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialThreeCRLF() throws IOException {
+ init(packet("message") + packet("message") + packet("message\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessagemessage\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialCR() throws IOException {
+ init(packet("message 0%\rmessage 100%"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\rmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialLF() throws IOException {
+ init(packet("message 0%\nmessage 100%"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialCRLF() throws IOException {
+ init(packet("message 0%\r\nmessage 100%"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\r\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialSplitCR() throws IOException {
+ init(packet("message") + "0006\001a" + packet(" 0%\rmessa")
+ + packet("ge 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\rmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialSplitLF() throws IOException {
+ init(packet("message") + "0006\001a" + packet(" 0%\nmessa")
+ + packet("ge 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialSplitCRLF() throws IOException {
+ init(packet("message") + "0006\001a" + packet(" 0%\r\nmessa")
+ + packet("ge 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\r\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressInterleaved() throws IOException {
+ init(packet("message 0%\r") + "0006\001a" + packet("message 10%")
+ + "0006\001b" + packet("\rmessage 100%\n"));
+ assertEquals('a', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertEquals('b', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\rmessage 10%\rmessage 100%\n",
+ messages.toString());
+ }
+
+ @Test
+ public void progressInterleavedPartial() throws IOException {
+ init(packet("message 0%\r") + "0006\001a" + packet("message 10%")
+ + "0006\001b" + packet("\rmessage 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertEquals('b', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\rmessage 10%\r", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\rmessage 10%\rmessage 100%\n",
+ messages.toString());
+ }
+
+ private String packet(String data) {
+ return String.format("%04x\002%s", Integer.valueOf(data.length() + 5),
+ data);
+ }
+
+ private void init(String packets) {
+ InputStream rawIn = new ByteArrayInputStream(
+ (packets + "0000").getBytes(StandardCharsets.UTF_8));
+ sideband = new SideBandInputStream(rawIn, null, messages, null);
+ }
+}
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 7baa215801..e9c587993b 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -4,14 +4,14 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.ui
Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: JavaSE-11
-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)"
+Export-Package: org.eclipse.jgit.awtui;version="6.2.0"
+Import-Package: org.eclipse.jgit.errors;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revplot;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.0,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.0,6.3.0)"
diff --git a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF
index 75f3d217ab..df93dc2133 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.ui - Sources
Bundle-SymbolicName: org.eclipse.jgit.ui.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.ui;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.ui;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 125e120b45..31c7149e84 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index eb8eb8bd65..a25685073d 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -3,12 +3,12 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit
Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Eclipse-ExtensibleAPI: true
-Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
- org.eclipse.jgit.api;version="6.1.1";
+Export-Package: org.eclipse.jgit.annotations;version="6.2.0",
+ org.eclipse.jgit.api;version="6.2.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.notes,
org.eclipse.jgit.dircache,
@@ -23,18 +23,18 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.revwalk.filter,
org.eclipse.jgit.blame,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="6.1.1";
+ org.eclipse.jgit.api.errors;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="6.1.1";
+ org.eclipse.jgit.attributes;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.blame;version="6.1.1";
+ org.eclipse.jgit.blame;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="6.1.1";
+ org.eclipse.jgit.diff;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.attributes,
org.eclipse.jgit.revwalk,
@@ -42,48 +42,49 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="6.1.1";
+ org.eclipse.jgit.dircache;version="6.2.0";
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.1.1";
+ org.eclipse.jgit.errors;version="6.2.0";
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.1.1";
+ org.eclipse.jgit.events;version="6.2.0";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="6.1.1",
- org.eclipse.jgit.gitrepo;version="6.1.1";
+ org.eclipse.jgit.fnmatch;version="6.2.0",
+ org.eclipse.jgit.gitrepo;version="6.2.0";
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.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";
+ org.eclipse.jgit.gitrepo.internal;version="6.2.0";x-internal:=true,
+ org.eclipse.jgit.hooks;version="6.2.0";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="6.2.0",
+ org.eclipse.jgit.ignore.internal;version="6.2.0";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="6.1.1";
+ org.eclipse.jgit.internal;version="6.2.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.diffmergetool;version="6.1.1";
+ org.eclipse.jgit.internal.diffmergetool;version="6.2.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.pgm.test,
- org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.fsck;version="6.1.1";
+ org.eclipse.jgit.pgm,
+ org.eclipse.egit.ui",
+ org.eclipse.jgit.internal.fsck;version="6.2.0";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.revwalk;version="6.1.1";
+ org.eclipse.jgit.internal.revwalk;version="6.2.0";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.storage.dfs;version="6.1.1";
+ org.eclipse.jgit.internal.storage.dfs;version="6.2.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.server,
org.eclipse.jgit.http.test,
org.eclipse.jgit.lfs.test",
- org.eclipse.jgit.internal.storage.file;version="6.1.1";
+ org.eclipse.jgit.internal.storage.file;version="6.2.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http,
@@ -92,32 +93,32 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.pgm,
org.eclipse.jgit.pgm.test,
org.eclipse.jgit.ssh.apache",
- org.eclipse.jgit.internal.storage.io;version="6.1.1";
+ org.eclipse.jgit.internal.storage.io;version="6.2.0";
x-friends:="org.eclipse.jgit.junit,
org.eclipse.jgit.test,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.pack;version="6.1.1";
+ org.eclipse.jgit.internal.storage.pack;version="6.2.0";
x-friends:="org.eclipse.jgit.junit,
org.eclipse.jgit.test,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.internal.storage.reftable;version="6.1.1";
+ org.eclipse.jgit.internal.storage.reftable;version="6.2.0";
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.1.1";x-internal:=true,
- org.eclipse.jgit.internal.transport.connectivity;version="6.1.1";
+ org.eclipse.jgit.internal.submodule;version="6.2.0";x-internal:=true,
+ org.eclipse.jgit.internal.transport.connectivity;version="6.2.0";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.http;version="6.1.1";
+ org.eclipse.jgit.internal.transport.http;version="6.2.0";
x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.parser;version="6.1.1";
+ org.eclipse.jgit.internal.transport.parser;version="6.2.0";
x-friends:="org.eclipse.jgit.http.server,
org.eclipse.jgit.test",
- org.eclipse.jgit.internal.transport.ssh;version="6.1.1";
+ org.eclipse.jgit.internal.transport.ssh;version="6.2.0";
x-friends:="org.eclipse.jgit.ssh.apache,
org.eclipse.jgit.ssh.jsch,
org.eclipse.jgit.test",
- org.eclipse.jgit.lib;version="6.1.1";
+ org.eclipse.jgit.lib;version="6.2.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util.sha1,
org.eclipse.jgit.dircache,
@@ -131,11 +132,12 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.util,
org.eclipse.jgit.submodule,
org.eclipse.jgit.util.time",
- org.eclipse.jgit.lib.internal;version="6.1.1";
+ org.eclipse.jgit.lib.internal;version="6.2.0";
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";
+ org.eclipse.jgit.pgm,
+ org.eclipse.egit.ui",
+ org.eclipse.jgit.logging;version="6.2.0",
+ org.eclipse.jgit.merge;version="6.2.0";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
@@ -144,40 +146,40 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.util,
org.eclipse.jgit.api,
org.eclipse.jgit.attributes",
- org.eclipse.jgit.nls;version="6.1.1",
- org.eclipse.jgit.notes;version="6.1.1";
+ org.eclipse.jgit.nls;version="6.2.0",
+ org.eclipse.jgit.notes;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="6.1.1";
+ org.eclipse.jgit.patch;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="6.1.1";
+ org.eclipse.jgit.revplot;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="6.1.1";
+ org.eclipse.jgit.revwalk;version="6.2.0";
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.1.1";
+ org.eclipse.jgit.revwalk.filter;version="6.2.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.lib,
org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="6.1.1";
+ org.eclipse.jgit.storage.file;version="6.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="6.1.1";
+ org.eclipse.jgit.storage.pack;version="6.2.0";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="6.1.1";
+ org.eclipse.jgit.submodule;version="6.2.0";
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.1.1";
+ org.eclipse.jgit.transport;version="6.2.0";
uses:="javax.crypto,
org.eclipse.jgit.util.io,
org.eclipse.jgit.lib,
@@ -190,21 +192,21 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.storage.pack,
org.eclipse.jgit.errors",
- org.eclipse.jgit.transport.http;version="6.1.1";
+ org.eclipse.jgit.transport.http;version="6.2.0";
uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="6.1.1";
+ org.eclipse.jgit.transport.resolver;version="6.2.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.lib",
- org.eclipse.jgit.treewalk;version="6.1.1";
+ org.eclipse.jgit.treewalk;version="6.2.0";
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.1.1";
+ org.eclipse.jgit.treewalk.filter;version="6.2.0";
uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="6.1.1";
+ org.eclipse.jgit.util;version="6.2.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.hooks,
org.eclipse.jgit.revwalk,
@@ -217,12 +219,12 @@ Export-Package: org.eclipse.jgit.annotations;version="6.1.1",
org.eclipse.jgit.treewalk,
javax.net.ssl,
org.eclipse.jgit.util.time",
- org.eclipse.jgit.util.io;version="6.1.1";
+ org.eclipse.jgit.util.io;version="6.2.0";
uses:="org.eclipse.jgit.attributes,
org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util.sha1;version="6.1.1",
- org.eclipse.jgit.util.time;version="6.1.1"
+ org.eclipse.jgit.util.sha1;version="6.2.0",
+ org.eclipse.jgit.util.time;version="6.2.0"
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 33e6156773..a418bc360d 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit - Sources
Bundle-SymbolicName: org.eclipse.jgit.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 6.1.1.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="6.1.1.qualifier";roots="."
+Bundle-Version: 6.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="6.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index f0e92b3894..2fbec2fbf1 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-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 e6f4e65e70..f0bb6c6c99 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -237,6 +237,9 @@ deleteTagUnexpectedResult=Delete tag returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported.
destinationIsNotAWildcard=Destination is not a wildcard.
detachedHeadDetected=HEAD is detached
+diffToolNotGivenError=No diff tool provided and no defaults configured.
+diffToolNotSpecifiedInGitAttributesError=Diff tool specified in git attributes cannot be found.
+diffToolNullError=Parameter for diff tool cannot be null.
dirCacheDoesNotHaveABackingFile=DirCache does not have a backing file
dirCacheFileIsNotLocked=DirCache {0} not locked
dirCacheIsNotLocked=DirCache is not locked
@@ -393,6 +396,7 @@ invalidLineInConfigFileWithParam=Invalid line in config file: {0}
invalidModeFor=Invalid mode {0} for {1} {2} in {3}.
invalidModeForPath=Invalid mode {0} for path {1}
invalidNameContainsDotDot=Invalid name (contains ".."): {0}
+invalidNegativeAndForce= RefSpec can't be negative and forceful.
invalidObject=Invalid {0} {1}: {2}
invalidOldIdSent=invalid old id sent
invalidPacketLineHeader=Invalid packet line header: {0}
@@ -456,6 +460,8 @@ mergeStrategyDoesNotSupportHeads=merge strategy {0} does not support {1} heads t
mergeUsingStrategyResultedInDescription=Merge of revisions {0} with base {1} using strategy {2} resulted in: {3}. {4}
mergeRecursiveConflictsWhenMergingCommonAncestors=Multiple common ancestors were found and merging them resulted in a conflict: {0}, {1}
mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b {2} found:\n count {3}"
+mergeToolNotGivenError=No merge tool provided and no defaults configured.
+mergeToolNullError=Parameter for merge tool cannot be null.
messageAndTaggerNotAllowedInUnannotatedTags = Unannotated tags cannot have a message or tagger
minutesAgo={0} minutes ago
mismatchOffset=mismatch offset for object {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 f88179ac1a..ceba89d166 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -30,6 +30,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.events.WorkingTreeModifiedEvent;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.CommitConfig;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
@@ -183,9 +184,13 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
String message;
if (unmergedPaths != null) {
+ CommitConfig cfg = repo.getConfig()
+ .get(CommitConfig.KEY);
+ message = srcCommit.getFullMessage();
+ char commentChar = cfg.getCommentChar(message);
message = new MergeMessageFormatter()
- .formatWithConflicts(srcCommit.getFullMessage(),
- unmergedPaths, '#');
+ .formatWithConflicts(message, unmergedPaths,
+ commentChar);
} 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 7a591aa3b5..3b3baf5a12 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -233,11 +233,25 @@ public class CommitCommand extends GitCommand<RevCommit> {
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();
+ char comments = (char) 0;
+ if (CleanupMode.STRIP.equals(cleanupMode)
+ || CleanupMode.SCISSORS.equals(cleanupMode)) {
+ if (commentChar == null) {
+ if (config == null) {
+ config = repo.getConfig().get(CommitConfig.KEY);
+ }
+ if (config.isAutoCommentChar()) {
+ // We're supposed to pick a character that isn't used,
+ // but then cleaning up won't remove any lines. So don't
+ // bother.
+ comments = (char) 0;
+ cleanupMode = CleanupMode.WHITESPACE;
+ } else {
+ comments = config.getCommentChar();
+ }
+ } else {
+ comments = commentChar.charValue();
+ }
}
message = CommitConfig.cleanText(message, cleanupMode, comments);
@@ -309,8 +323,14 @@ public class CommitCommand extends GitCommand<RevCommit> {
private void sign(CommitBuilder commit) throws ServiceUnavailableException,
CanceledException, UnsupportedSigningFormatException {
if (gpgSigner == null) {
- throw new ServiceUnavailableException(
- JGitText.get().signingServiceUnavailable);
+ gpgSigner = GpgSigner.getDefault();
+ if (gpgSigner == null) {
+ throw new ServiceUnavailableException(
+ JGitText.get().signingServiceUnavailable);
+ }
+ }
+ if (signingKey == null) {
+ signingKey = gpgConfig.getSigningKey();
}
if (gpgSigner instanceof GpgObjectSigner) {
((GpgObjectSigner) gpgSigner).signObject(commit,
@@ -645,12 +665,6 @@ public class CommitCommand extends GitCommand<RevCommit> {
signCommit = gpgConfig.isSignCommits() ? Boolean.TRUE
: Boolean.FALSE;
}
- if (signingKey == null) {
- signingKey = gpgConfig.getSigningKey();
- }
- if (gpgSigner == null) {
- gpgSigner = GpgSigner.getDefault();
- }
}
private boolean isMergeDuringRebase(RepositoryState state) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
index 0c691062f9..c3415581ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2020 Christoph Brill <egore911@egore911.de> and others
+ * Copyright (C) 2011, 2022 Christoph Brill <egore911@egore911.de> 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
@@ -9,6 +9,7 @@
*/
package org.eclipse.jgit.api;
+import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -20,8 +21,8 @@ import java.util.Map;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.NotSupportedException;
-import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
@@ -30,6 +31,8 @@ import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.UrlConfig;
+import org.eclipse.jgit.util.SystemReader;
/**
* The ls-remote command
@@ -153,7 +156,7 @@ public class LsRemoteCommand extends
try (Transport transport = repo != null
? Transport.open(repo, remote)
- : Transport.open(new URIish(remote))) {
+ : Transport.open(new URIish(translate(remote)))) {
transport.setOptionUploadPack(uploadPack);
configure(transport);
Collection<RefSpec> refSpecs = new ArrayList<>(1);
@@ -185,11 +188,16 @@ public class LsRemoteCommand extends
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfLsRemoteCommand,
e);
- } catch (TransportException e) {
+ } catch (IOException | ConfigInvalidException e) {
throw new org.eclipse.jgit.api.errors.TransportException(
- e.getMessage(),
- e);
+ e.getMessage(), e);
}
}
+ private String translate(String uri)
+ throws IOException, ConfigInvalidException {
+ UrlConfig urls = new UrlConfig(
+ SystemReader.getInstance().getUserConfig());
+ return urls.replace(uri);
+ }
}
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 ce068b6306..ed4a5342b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -34,6 +34,7 @@ import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.events.WorkingTreeModifiedEvent;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.CommitConfig;
import org.eclipse.jgit.lib.Config.ConfigEnum;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -404,8 +405,11 @@ public class MergeCommand extends GitCommand<MergeResult> {
MergeStatus.FAILED, mergeStrategy, lowLevelResults,
failingPaths, null);
}
+ CommitConfig cfg = repo.getConfig().get(CommitConfig.KEY);
+ char commentChar = cfg.getCommentChar(message);
String mergeMessageWithConflicts = new MergeMessageFormatter()
- .formatWithConflicts(mergeMessage, unmergedPaths, '#');
+ .formatWithConflicts(mergeMessage, unmergedPaths,
+ commentChar);
repo.writeMergeCommitMsg(mergeMessageWithConflicts);
return new MergeResult(null, merger.getBaseCommitId(),
new ObjectId[] { headCommit.getId(),
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 2b0d8ce1c9..4e0d9d78c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -449,7 +449,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
String oldMessage = commitToPick.getFullMessage();
CleanupMode mode = commitConfig.resolve(CleanupMode.DEFAULT, true);
boolean[] doChangeId = { false };
- String newMessage = editCommitMessage(doChangeId, oldMessage, mode);
+ String newMessage = editCommitMessage(doChangeId, oldMessage, mode,
+ commitConfig.getCommentChar(oldMessage));
try (Git git = new Git(repo)) {
newHead = git.commit()
.setMessage(newMessage)
@@ -494,12 +495,12 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
private String editCommitMessage(boolean[] doChangeId, String message,
- @NonNull CleanupMode mode) {
+ @NonNull CleanupMode mode, char commentChar) {
String newMessage;
CommitConfig.CleanupMode cleanup;
if (interactiveHandler instanceof InteractiveHandler2) {
InteractiveHandler2.ModifyResult modification = ((InteractiveHandler2) interactiveHandler)
- .editCommitMessage(message, mode, '#');
+ .editCommitMessage(message, mode, commentChar);
newMessage = modification.getMessage();
cleanup = modification.getCleanupMode();
if (CleanupMode.DEFAULT.equals(cleanup)) {
@@ -511,7 +512,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
cleanup = CommitConfig.CleanupMode.STRIP;
doChangeId[0] = false;
}
- return CommitConfig.cleanText(newMessage, cleanup, '#');
+ return CommitConfig.cleanText(newMessage, cleanup, commentChar);
}
private RebaseResult cherryPickCommit(RevCommit commitToPick)
@@ -808,8 +809,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
if (isLast) {
boolean[] doChangeId = { false };
if (sequenceContainsSquash) {
+ char commentChar = commitMessage.charAt(0);
commitMessage = editCommitMessage(doChangeId, commitMessage,
- CleanupMode.STRIP);
+ CleanupMode.STRIP, commentChar);
}
retNewHead = git.commit()
.setMessage(commitMessage)
@@ -829,30 +831,60 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
}
@SuppressWarnings("nls")
- private static String composeSquashMessage(boolean isSquash,
+ private String composeSquashMessage(boolean isSquash,
RevCommit commitToPick, String currSquashMessage, int count) {
StringBuilder sb = new StringBuilder();
String ordinal = getOrdinal(count);
- sb.setLength(0);
- sb.append("# This is a combination of ").append(count)
- .append(" commits.\n");
- // Add the previous message without header (i.e first line)
- sb.append(currSquashMessage
- .substring(currSquashMessage.indexOf('\n') + 1));
- sb.append("\n");
- if (isSquash) {
- sb.append("# This is the ").append(count).append(ordinal)
- .append(" commit message:\n");
- sb.append(commitToPick.getFullMessage());
+ // currSquashMessage is always non-empty here, and the first character
+ // is the comment character used so far.
+ char commentChar = currSquashMessage.charAt(0);
+ String newMessage = commitToPick.getFullMessage();
+ if (!isSquash) {
+ sb.append(commentChar).append(" This is a combination of ")
+ .append(count).append(" commits.\n");
+ // Add the previous message without header (i.e first line)
+ sb.append(currSquashMessage
+ .substring(currSquashMessage.indexOf('\n') + 1));
+ sb.append('\n');
+ sb.append(commentChar).append(" The ").append(count).append(ordinal)
+ .append(" commit message will be skipped:\n")
+ .append(commentChar).append(' ');
+ sb.append(newMessage.replaceAll("([\n\r])",
+ "$1" + commentChar + ' '));
} else {
- sb.append("# The ").append(count).append(ordinal)
- .append(" commit message will be skipped:\n# ");
- sb.append(commitToPick.getFullMessage().replaceAll("([\n\r])",
- "$1# "));
+ String currentMessage = currSquashMessage;
+ if (commitConfig.isAutoCommentChar()) {
+ // Figure out a new comment character taking into account the
+ // new message
+ String cleaned = CommitConfig.cleanText(currentMessage,
+ CommitConfig.CleanupMode.STRIP, commentChar) + '\n'
+ + newMessage;
+ char newCommentChar = commitConfig.getCommentChar(cleaned);
+ if (newCommentChar != commentChar) {
+ currentMessage = replaceCommentChar(currentMessage,
+ commentChar, newCommentChar);
+ commentChar = newCommentChar;
+ }
+ }
+ sb.append(commentChar).append(" This is a combination of ")
+ .append(count).append(" commits.\n");
+ // Add the previous message without header (i.e first line)
+ sb.append(
+ currentMessage.substring(currentMessage.indexOf('\n') + 1));
+ sb.append('\n');
+ sb.append(commentChar).append(" This is the ").append(count)
+ .append(ordinal).append(" commit message:\n");
+ sb.append(newMessage);
}
return sb.toString();
}
+ private String replaceCommentChar(String message, char oldChar,
+ char newChar) {
+ // (?m) - Switch on multi-line matching; \h - horizontal whitespace
+ return message.replaceAll("(?m)^(\\h*)" + oldChar, "$1" + newChar); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
private static String getOrdinal(int count) {
switch (count % 10) {
case 1:
@@ -886,10 +918,11 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
private void initializeSquashFixupFile(String messageFile,
String fullMessage) throws IOException {
- rebaseState
- .createFile(
- messageFile,
- "# This is a combination of 1 commits.\n# The first commit's message is:\n" + fullMessage); //$NON-NLS-1$);
+ char commentChar = commitConfig.getCommentChar(fullMessage);
+ rebaseState.createFile(messageFile,
+ commentChar + " This is a combination of 1 commits.\n" //$NON-NLS-1$
+ + commentChar + " The first commit's message is:\n" //$NON-NLS-1$
+ + fullMessage);
}
private String getOurCommitName() {
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 db88ad8dc9..513f579b67 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -30,6 +30,7 @@ import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.events.WorkingTreeModifiedEvent;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.CommitConfig;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
@@ -185,9 +186,12 @@ public class RevertCommand extends GitCommand<RevCommit> {
MergeStatus.CONFLICTING, strategy,
merger.getMergeResults(), failingPaths, null);
if (!merger.failed() && !unmergedPaths.isEmpty()) {
+ CommitConfig config = repo.getConfig()
+ .get(CommitConfig.KEY);
+ char commentChar = config.getCommentChar(newMessage);
String message = new MergeMessageFormatter()
.formatWithConflicts(newMessage,
- merger.getUnmergedPaths(), '#');
+ merger.getUnmergedPaths(), commentChar);
repo.writeRevertHead(srcCommit.getId());
repo.writeMergeCommitMsg(message);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
index 1a41df3d0a..64ff19c9c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2020 Google Inc. and others
+ * Copyright (C) 2010, 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
@@ -91,6 +91,29 @@ public abstract class ContentSource {
public abstract ObjectLoader open(String path, ObjectId id)
throws IOException;
+ /**
+ * Closes the used resources like ObjectReader, TreeWalk etc. Default
+ * implementation does nothing.
+ *
+ * @since 6.2
+ */
+ public void close() {
+ // Do nothing
+ }
+
+ /**
+ * Checks if the source is from "working tree", so it can be accessed as a
+ * file directly.
+ *
+ * @since 6.2
+ *
+ * @return true if working tree source and false otherwise (loader must be
+ * used)
+ */
+ public boolean isWorkingTreeSource() {
+ return false;
+ }
+
private static class ObjectReaderSource extends ContentSource {
private final ObjectReader reader;
@@ -111,6 +134,16 @@ public abstract class ContentSource {
public ObjectLoader open(String path, ObjectId id) throws IOException {
return reader.open(id, Constants.OBJ_BLOB);
}
+
+ @Override
+ public void close() {
+ reader.close();
+ }
+
+ @Override
+ public boolean isWorkingTreeSource() {
+ return false;
+ }
}
private static class WorkingTreeSource extends ContentSource {
@@ -194,6 +227,16 @@ public abstract class ContentSource {
throw new FileNotFoundException(path);
}
}
+
+ @Override
+ public void close() {
+ tw.close();
+ }
+
+ @Override
+ public boolean isWorkingTreeSource() {
+ return true;
+ }
}
/** A pair of sources to access the old and new sides of a DiffEntry. */
@@ -261,5 +304,37 @@ public abstract class ContentSource {
throw new IllegalArgumentException();
}
}
+
+ /**
+ * Closes used resources.
+ *
+ * @since 6.2
+ */
+ public void close() {
+ oldSource.close();
+ newSource.close();
+ }
+
+ /**
+ * Checks if source (side) is a "working tree".
+ *
+ * @since 6.2
+ *
+ * @param side
+ * which side of the entry to read (OLD or NEW).
+ * @return is the source a "working tree"
+ *
+ */
+ public boolean isWorkingTreeSource(DiffEntry.Side side) {
+ switch (side) {
+ case OLD:
+ return oldSource.isWorkingTreeSource();
+ case NEW:
+ return newSource.isWorkingTreeSource();
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
}
}
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 3d50a82155..f6fc393c45 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -26,9 +26,9 @@ import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.time.Instant;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -113,7 +113,7 @@ public class DirCacheCheckout {
private Repository repo;
- private HashMap<String, CheckoutMetadata> updated = new HashMap<>();
+ private Map<String, CheckoutMetadata> updated = new LinkedHashMap<>();
private ArrayList<String> conflicts = new ArrayList<>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
index 535c6b9483..43dbc37f4f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Obeo. and others
+ * Copyright (C) 2015, 2022 Obeo 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
@@ -38,6 +38,8 @@ public class PrePushHook extends GitHook<String> {
private String refs;
+ private boolean dryRun;
+
/**
* Constructor for PrePushHook
* <p>
@@ -145,6 +147,27 @@ public class PrePushHook extends GitHook<String> {
}
/**
+ * Sets whether the push is a dry run.
+ *
+ * @param dryRun
+ * {@code true} if the push is a dry run, {@code false} otherwise
+ * @since 6.2
+ */
+ public void setDryRun(boolean dryRun) {
+ this.dryRun = dryRun;
+ }
+
+ /**
+ * Tells whether the push is a dry run.
+ *
+ * @return {@code true} if the push is a dry run, {@code false} otherwise
+ * @since 6.2
+ */
+ protected boolean isDryRun() {
+ return dryRun;
+ }
+
+ /**
* Set Refs
*
* @param toRefs
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 16b3f372ef..17e359de49 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -265,6 +265,9 @@ public class JGitText extends TranslationBundle {
/***/ public String deletingNotSupported;
/***/ public String destinationIsNotAWildcard;
/***/ public String detachedHeadDetected;
+ /***/ public String diffToolNotGivenError;
+ /***/ public String diffToolNotSpecifiedInGitAttributesError;
+ /***/ public String diffToolNullError;
/***/ public String dirCacheDoesNotHaveABackingFile;
/***/ public String dirCacheFileIsNotLocked;
/***/ public String dirCacheIsNotLocked;
@@ -421,6 +424,7 @@ public class JGitText extends TranslationBundle {
/***/ public String invalidModeFor;
/***/ public String invalidModeForPath;
/***/ public String invalidNameContainsDotDot;
+ /***/ public String invalidNegativeAndForce;
/***/ public String invalidObject;
/***/ public String invalidOldIdSent;
/***/ public String invalidPacketLineHeader;
@@ -484,6 +488,8 @@ public class JGitText extends TranslationBundle {
/***/ public String mergeUsingStrategyResultedInDescription;
/***/ public String mergeRecursiveConflictsWhenMergingCommonAncestors;
/***/ public String mergeRecursiveTooManyMergeBasesFor;
+ /***/ public String mergeToolNotGivenError;
+ /***/ public String mergeToolNullError;
/***/ public String messageAndTaggerNotAllowedInUnannotatedTags;
/***/ public String minutesAgo;
/***/ public String mismatchOffset;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandExecutor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandExecutor.java
new file mode 100644
index 0000000000..668adeab65
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandExecutor.java
@@ -0,0 +1,239 @@
+/*
+ * 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.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.eclipse.jgit.util.FS_POSIX;
+import org.eclipse.jgit.util.FS_Win32;
+import org.eclipse.jgit.util.FS_Win32_Cygwin;
+import org.eclipse.jgit.util.StringUtils;
+
+/**
+ * Runs a command with help of FS.
+ */
+public class CommandExecutor {
+
+ private FS fs;
+
+ private boolean checkExitCode;
+
+ private File commandFile;
+
+ private boolean useMsys2;
+
+ /**
+ * @param fs
+ * the file system
+ * @param checkExitCode
+ * should the exit code be checked for errors ?
+ */
+ public CommandExecutor(FS fs, boolean checkExitCode) {
+ this.fs = fs;
+ this.checkExitCode = checkExitCode;
+ }
+
+ /**
+ * @param command
+ * the command string
+ * @param workingDir
+ * the working directory
+ * @param env
+ * the environment
+ * @return the execution result
+ * @throws ToolException
+ * @throws InterruptedException
+ * @throws IOException
+ */
+ public ExecutionResult run(String command, File workingDir,
+ Map<String, String> env)
+ throws ToolException, IOException, InterruptedException {
+ String[] commandArray = createCommandArray(command);
+ try {
+ ProcessBuilder pb = fs.runInShell(commandArray[0],
+ Arrays.copyOfRange(commandArray, 1, commandArray.length));
+ pb.directory(workingDir);
+ Map<String, String> envp = pb.environment();
+ if (env != null) {
+ envp.putAll(env);
+ }
+ ExecutionResult result = fs.execute(pb, null);
+ int rc = result.getRc();
+ if (rc != 0) {
+ boolean execError = isCommandExecutionError(rc);
+ if (checkExitCode || execError) {
+ throw new ToolException(
+ "JGit: tool execution return code: " + rc + "\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + "checkExitCode: " + checkExitCode + "\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + "execError: " + execError + "\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + "stderr: \n" //$NON-NLS-1$
+ + new String(
+ result.getStderr().toByteArray()),
+ result, execError);
+ }
+ }
+ return result;
+ } finally {
+ deleteCommandArray();
+ }
+ }
+
+ /**
+ * @param path
+ * the executable path
+ * @param workingDir
+ * the working directory
+ * @param env
+ * the environment
+ * @return the execution result
+ * @throws ToolException
+ * @throws InterruptedException
+ * @throws IOException
+ */
+ public boolean checkExecutable(String path, File workingDir,
+ Map<String, String> env)
+ throws ToolException, IOException, InterruptedException {
+ checkUseMsys2(path);
+ String command = null;
+ if (fs instanceof FS_Win32 && !useMsys2) {
+ Path p = Paths.get(path);
+ // Win32 (and not cygwin or MSYS2) where accepts only command / exe
+ // name as parameter
+ // so check if exists and executable in this case
+ if (p.isAbsolute() && Files.isExecutable(p)) {
+ return true;
+ }
+ // try where command for all other cases
+ command = "where " + ExternalToolUtils.quotePath(path); //$NON-NLS-1$
+ } else {
+ command = "which " + ExternalToolUtils.quotePath(path); //$NON-NLS-1$
+ }
+ boolean available = true;
+ try {
+ ExecutionResult rc = run(command, workingDir, env);
+ if (rc.getRc() != 0) {
+ available = false;
+ }
+ } catch (IOException | InterruptedException | NoWorkTreeException
+ | ToolException e) {
+ // no op: is true to not hide possible tools from user
+ }
+ return available;
+ }
+
+ private void deleteCommandArray() {
+ deleteCommandFile();
+ }
+
+ private String[] createCommandArray(String command)
+ throws ToolException, IOException {
+ String[] commandArray = null;
+ checkUseMsys2(command);
+ createCommandFile(command);
+ if (fs instanceof FS_POSIX) {
+ commandArray = new String[1];
+ commandArray[0] = commandFile.getCanonicalPath();
+ } else if (fs instanceof FS_Win32) {
+ if (useMsys2) {
+ commandArray = new String[3];
+ commandArray[0] = "bash.exe"; //$NON-NLS-1$
+ commandArray[1] = "-c"; //$NON-NLS-1$
+ commandArray[2] = commandFile.getCanonicalPath().replace("\\", //$NON-NLS-1$
+ "/"); //$NON-NLS-1$
+ } else {
+ commandArray = new String[1];
+ commandArray[0] = commandFile.getCanonicalPath();
+ }
+ } else if (fs instanceof FS_Win32_Cygwin) {
+ commandArray = new String[1];
+ commandArray[0] = commandFile.getCanonicalPath().replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ throw new ToolException(
+ "JGit: file system not supported: " + fs.toString()); //$NON-NLS-1$
+ }
+ return commandArray;
+ }
+
+ private void checkUseMsys2(String command) {
+ useMsys2 = false;
+ String useMsys2Str = System.getProperty("jgit.usemsys2bash"); //$NON-NLS-1$
+ if (!StringUtils.isEmptyOrNull(useMsys2Str)) {
+ if (useMsys2Str.equalsIgnoreCase("auto")) { //$NON-NLS-1$
+ useMsys2 = command.contains(".sh"); //$NON-NLS-1$
+ } else {
+ useMsys2 = Boolean.parseBoolean(useMsys2Str);
+ }
+ }
+ }
+
+ private void createCommandFile(String command)
+ throws ToolException, IOException {
+ String fileExtension = null;
+ if (useMsys2 || fs instanceof FS_POSIX
+ || fs instanceof FS_Win32_Cygwin) {
+ fileExtension = ".sh"; //$NON-NLS-1$
+ } else if (fs instanceof FS_Win32) {
+ fileExtension = ".cmd"; //$NON-NLS-1$
+ command = "@echo off" + System.lineSeparator() + command //$NON-NLS-1$
+ + System.lineSeparator() + "exit /B %ERRORLEVEL%"; //$NON-NLS-1$
+ } else {
+ throw new ToolException(
+ "JGit: file system not supported: " + fs.toString()); //$NON-NLS-1$
+ }
+ commandFile = File.createTempFile(".__", //$NON-NLS-1$
+ "__jgit_tool" + fileExtension); //$NON-NLS-1$
+ try (OutputStream outStream = new FileOutputStream(commandFile)) {
+ byte[] strToBytes = command.getBytes();
+ outStream.write(strToBytes);
+ outStream.close();
+ }
+ commandFile.setExecutable(true);
+ }
+
+ private void deleteCommandFile() {
+ if (commandFile != null && commandFile.exists()) {
+ commandFile.delete();
+ }
+ }
+
+ private boolean isCommandExecutionError(int rc) {
+ if (useMsys2 || fs instanceof FS_POSIX
+ || fs instanceof FS_Win32_Cygwin) {
+ // 126: permission for executing command denied
+ // 127: command not found
+ if ((rc == 126) || (rc == 127)) {
+ return true;
+ }
+ }
+ else if (fs instanceof FS_Win32) {
+ // 9009, 0x2331: Program is not recognized as an internal or
+ // external command, operable program or batch file. Indicates that
+ // command, application name or path has been misspelled when
+ // configuring the Action.
+ if (rc == 9009) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
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
index 509515c37a..00dec32718 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java
@@ -111,7 +111,7 @@ public enum CommandLineDiffTool {
* See: <a href=
* "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
*/
- gvimdiff("gviewdiff", "\"$LOCAL\" \"$REMOTE\""),
+ gvimdiff("gvimdiff", "\"$LOCAL\" \"$REMOTE\""),
/**
* See: <a href=
* "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
@@ -160,7 +160,7 @@ public enum CommandLineDiffTool {
* See: <a href=
* "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
*/
- vimdiff("viewdiff", gvimdiff),
+ vimdiff("vimdiff", gvimdiff),
/**
* See: <a href=
* "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java
new file mode 100644
index 0000000000..3a22124328
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2018-2022, 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 merge tools.
+ *
+ * Adds same merge tools as also pre-defined in C-Git see "git-core\mergetools\"
+ * see links to command line parameter description for the tools
+ *
+ * <pre>
+ * araxis
+ * bc
+ * bc3
+ * codecompare
+ * deltawalker
+ * diffmerge
+ * diffuse
+ * ecmerge
+ * emerge
+ * examdiff
+ * guiffy
+ * gvimdiff
+ * gvimdiff2
+ * gvimdiff3
+ * kdiff3
+ * kompare
+ * meld
+ * opendiff
+ * p4merge
+ * tkdiff
+ * tortoisemerge
+ * vimdiff
+ * vimdiff2
+ * vimdiff3
+ * winmerge
+ * xxdiff
+ * </pre>
+ *
+ */
+@SuppressWarnings("nls")
+public enum CommandLineMergeTool {
+ /**
+ * 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 -merge -3 -a1 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"",
+ "-wait -2 \"$LOCAL\" \"$REMOTE\" \"$MERGED\"",
+ false),
+ /**
+ * 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\" \"$BASE\" --mergeoutput=\"$MERGED\"",
+ "\"$LOCAL\" \"$REMOTE\" --mergeoutput=\"$MERGED\"",
+ false),
+ /**
+ * 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?merging_via_command_line.htm">https://www.devart.com/codecompare/docs/index.html?merging_via_command_line.htm</a>
+ */
+ codecompare("CodeMerge",
+ "-MF=\"$LOCAL\" -TF=\"$REMOTE\" -BF=\"$BASE\" -RF=\"$MERGED\"",
+ "-MF=\"$LOCAL\" -TF=\"$REMOTE\" -RF=\"$MERGED\"",
+ false),
+ /**
+ * See: <a href=
+ * "https://www.deltawalker.com/integrate/command-line">https://www.deltawalker.com/integrate/command-line</a>
+ * <p>
+ * Hint: $(pwd) command must be defined
+ * </p>
+ */
+ deltawalker("DeltaWalker",
+ "\"$LOCAL\" \"$REMOTE\" \"$BASE\" -pwd=\"$(pwd)\" -merged=\"$MERGED\"",
+ "\"$LOCAL\" \"$REMOTE\" -pwd=\"$(pwd)\" -merged=\"$MERGED\"",
+ true),
+ /**
+ * See: <a href=
+ * "https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html">https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html</a>
+ */
+ diffmerge("diffmerge", //$NON-NLS-1$
+ "--merge --result=\"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"",
+ "--merge --result=\"$MERGED\" \"$LOCAL\" \"$REMOTE\"",
+ true),
+ /**
+ * See: <a href=
+ * "http://diffuse.sourceforge.net/manual.html#introduction-usage">http://diffuse.sourceforge.net/manual.html#introduction-usage</a>
+ * <p>
+ * Hint: check the ' | cat' for the call
+ * </p>
+ */
+ diffuse("diffuse", "\"$LOCAL\" \"$MERGED\" \"$REMOTE\" \"$BASE\"",
+ "\"$LOCAL\" \"$MERGED\" \"$REMOTE\"", false),
+ /**
+ * 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=merge3 \"$BASE\" \"$LOCAL\" \"$REMOTE\" --to=\"$MERGED\"",
+ "--default --mode=merge2 \"$LOCAL\" \"$REMOTE\" --to=\"$MERGED\"",
+ false),
+ /**
+ * 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>
+ * <p>
+ * Hint: $(basename) command must be defined
+ * </p>
+ */
+ emerge("emacs",
+ "-f emerge-files-with-ancestor-command \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$(basename \"$MERGED\")\"",
+ "-f emerge-files-command \"$LOCAL\" \"$REMOTE\" \"$(basename \"$MERGED\")\"",
+ true),
+ /**
+ * 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",
+ "-merge \"$LOCAL\" \"$BASE\" \"$REMOTE\" -o:\"$MERGED\" -nh",
+ "-merge \"$LOCAL\" \"$REMOTE\" -o:\"$MERGED\" -nh",
+ false),
+ /**
+ * See: <a href=
+ * "https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html">https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html</a>
+ */
+ guiffy("guiffy", "-s \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"",
+ "-m \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", true),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ gvimdiff("gvim",
+ "-f -d -c '4wincmd w | wincmd J' \"$LOCAL\" \"$BASE\" \"$REMOTE\" \"$MERGED\"",
+ "-f -d -c 'wincmd l' \"$LOCAL\" \"$MERGED\" \"$REMOTE\"",
+ true),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ gvimdiff2("gvim", "-f -d -c 'wincmd l' \"$LOCAL\" \"$MERGED\" \"$REMOTE\"",
+ "-f -d -c 'wincmd l' \"$LOCAL\" \"$MERGED\" \"$REMOTE\"", true),
+ /**
+ * See: <a href= "http://vimdoc.sourceforge.net/htmldoc/diff.html"></a>
+ */
+ gvimdiff3("gvim",
+ "-f -d -c 'hid | hid | hid' \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"",
+ "-f -d -c 'hid | hid' \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", true),
+ /**
+ * See: <a href=
+ * "http://kdiff3.sourceforge.net/doc/documentation.html">http://kdiff3.sourceforge.net/doc/documentation.html</a>
+ */
+ kdiff3("kdiff3",
+ "--auto --L1 \"$MERGED (Base)\" --L2 \"$MERGED (Local)\" --L3 \"$MERGED (Remote)\" -o \"$MERGED\" \"$BASE\" \"$LOCAL\" \"$REMOTE\"",
+ "--auto --L1 \"$MERGED (Local)\" --L2 \"$MERGED (Remote)\" -o \"$MERGED\" \"$LOCAL\" \"$REMOTE\"",
+ true),
+ /**
+ * See: <a href=
+ * "http://meldmerge.org/help/file-mode.html">http://meldmerge.org/help/file-mode.html</a>
+ * <p>
+ * Hint: use meld with output option only (new versions)
+ * </p>
+ */
+ meld("meld", "--output=\"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"",
+ "\"$LOCAL\" \"$MERGED\" \"$REMOTE\"",
+ false),
+ /**
+ * 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\" -ancestor \"$BASE\" -merge \"$MERGED\"",
+ "\"$LOCAL\" \"$REMOTE\" -merge \"$MERGED\"",
+ false),
+ /**
+ * 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>
+ * <p>
+ * Hint: check how to fix "no base present" / create_virtual_base problem
+ * </p>
+ */
+ p4merge("p4merge", "\"$BASE\" \"$REMOTE\" \"$LOCAL\" \"$MERGED\"",
+ "\"$REMOTE\" \"$LOCAL\" \"$MERGED\"", false),
+ /**
+ * 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", "-a \"$BASE\" -o \"$MERGED\" \"$LOCAL\" \"$REMOTE\"",
+ "-o \"$MERGED\" \"$LOCAL\" \"$REMOTE\"",
+ true),
+ /**
+ * See: <a href=
+ * "https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics">https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics</a>
+ * <p>
+ * Hint: merge without base is not supported
+ * </p>
+ * <p>
+ * Hint: cannot diff
+ * </p>
+ */
+ tortoisegitmerge("tortoisegitmerge",
+ "-base \"$BASE\" -mine \"$LOCAL\" -theirs \"$REMOTE\" -merged \"$MERGED\"",
+ null, false),
+ /**
+ * See: <a href=
+ * "https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics">https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics</a>
+ * <p>
+ * Hint: merge without base is not supported
+ * </p>
+ * <p>
+ * Hint: cannot diff
+ * </p>
+ */
+ tortoisemerge("tortoisemerge",
+ "-base:\"$BASE\" -mine:\"$LOCAL\" -theirs:\"$REMOTE\" -merged:\"$MERGED\"",
+ null, false),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ vimdiff("vim", gvimdiff),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ vimdiff2("vim", gvimdiff2),
+ /**
+ * See: <a href=
+ * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a>
+ */
+ vimdiff3("vim", gvimdiff3),
+ /**
+ * 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 -dl Local -dr Remote \"$LOCAL\" \"$REMOTE\" \"$MERGED\"",
+ "-u -e -dl Local -dr Remote \"$LOCAL\" \"$REMOTE\" \"$MERGED\"",
+ false),
+ /**
+ * See: <a href=
+ * "http://furius.ca/xxdiff/doc/xxdiff-doc.html">http://furius.ca/xxdiff/doc/xxdiff-doc.html</a>
+ */
+ xxdiff("xxdiff",
+ "-X --show-merged-pane -R 'Accel.SaveAsMerged: \"Ctrl+S\"' -R 'Accel.Search: \"Ctrl+F\"' -R 'Accel.SearchForward: \"Ctrl+G\"' --merged-file \"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"",
+ "-X -R 'Accel.SaveAsMerged: \"Ctrl+S\"' -R 'Accel.Search: \"Ctrl+F\"' -R 'Accel.SearchForward: \"Ctrl+G\"' --merged-file \"$MERGED\" \"$LOCAL\" \"$REMOTE\"",
+ false);
+
+ CommandLineMergeTool(String path, String parametersWithBase,
+ String parametersWithoutBase,
+ boolean exitCodeTrustable) {
+ this.path = path;
+ this.parametersWithBase = parametersWithBase;
+ this.parametersWithoutBase = parametersWithoutBase;
+ this.exitCodeTrustable = exitCodeTrustable;
+ }
+
+ CommandLineMergeTool(CommandLineMergeTool from) {
+ this(from.getPath(), from.getParameters(true),
+ from.getParameters(false), from.isExitCodeTrustable());
+ }
+
+ CommandLineMergeTool(String path, CommandLineMergeTool from) {
+ this(path, from.getParameters(true), from.getParameters(false),
+ from.isExitCodeTrustable());
+ }
+
+ private final String path;
+
+ private final String parametersWithBase;
+
+ private final String parametersWithoutBase;
+
+ private final boolean exitCodeTrustable;
+
+ /**
+ * @return path
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @param withBase
+ * return parameters with base present?
+ * @return parameters with or without base present
+ */
+ public String getParameters(boolean withBase) {
+ if (withBase) {
+ return parametersWithBase;
+ }
+ return parametersWithoutBase;
+ }
+
+ /**
+ * @return parameters
+ */
+ public boolean isExitCodeTrustable() {
+ return exitCodeTrustable;
+ }
+
+ /**
+ * @return true if command with base present is valid, false otherwise
+ */
+ public boolean canMergeWithoutBasePresent() {
+ return parametersWithoutBase != null;
+ }
+
+}
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
index 551f634f2d..c8b04f90f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java
@@ -49,9 +49,10 @@ public class DiffToolConfig {
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,
+ prompt = rc.getBoolean(CONFIG_DIFFTOOL_SECTION, toolName,
+ CONFIG_KEY_PROMPT,
true);
- String trustStr = rc.getString(CONFIG_DIFFTOOL_SECTION, null,
+ String trustStr = rc.getString(CONFIG_DIFFTOOL_SECTION, toolName,
CONFIG_KEY_TRUST_EXIT_CODE);
if (trustStr != null) {
trustExitCode = Boolean.parseBoolean(trustStr)
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
index 39729a4eec..7cedd82995 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2019, Tim Neumann <tim.neumann@advantest.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
@@ -10,24 +11,43 @@
package org.eclipse.jgit.internal.diffmergetool;
-import java.util.TreeMap;
+import java.io.File;
+import java.io.IOException;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
+import java.util.TreeMap;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.eclipse.jgit.util.StringUtils;
/**
* Manages diff tools.
*/
public class DiffTools {
+ private final FS fs;
+
+ private final File gitDir;
+
+ private final File workTree;
+
private final DiffToolConfig config;
- private Map<String, ExternalDiffTool> predefinedTools;
+ private final Repository repo;
- private Map<String, ExternalDiffTool> userDefinedTools;
+ private final Map<String, ExternalDiffTool> predefinedTools;
+
+ private final Map<String, ExternalDiffTool> userDefinedTools;
/**
* Creates the external diff-tools manager for given repository.
@@ -36,46 +56,220 @@ public class DiffTools {
* the repository
*/
public DiffTools(Repository repo) {
- config = repo.getConfig().get(DiffToolConfig.KEY);
- setupPredefinedTools();
- setupUserDefinedTools();
+ this(repo, repo.getConfig());
+ }
+
+ /**
+ * Creates the external merge-tools manager for given configuration.
+ *
+ * @param config
+ * the git configuration
+ */
+ public DiffTools(StoredConfig config) {
+ this(null, config);
+ }
+
+ private DiffTools(Repository repo, StoredConfig config) {
+ this.repo = repo;
+ this.config = config.get(DiffToolConfig.KEY);
+ this.gitDir = repo == null ? null : repo.getDirectory();
+ this.fs = repo == null ? FS.DETECTED : repo.getFS();
+ this.workTree = repo == null ? null : repo.getWorkTree();
+ predefinedTools = setupPredefinedTools();
+ userDefinedTools = setupUserDefinedTools(predefinedTools);
}
/**
* 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 localFile
+ * The local/left version of the file.
+ * @param remoteFile
+ * The remote/right version of the file.
* @param toolName
- * the selected tool name (can be null)
+ * Optionally the name of the tool to use. If not given the
+ * default tool will be used.
* @param prompt
- * the prompt option
+ * Optionally a flag whether to prompt the user before compare.
+ * If not given the default will be used.
* @param gui
- * the GUI option
+ * A flag whether to prefer a gui tool.
+ * @param trustExitCode
+ * Optionally a flag whether to trust the exit code of the tool.
+ * If not given the default will be used.
+ * @param promptHandler
+ * The handler to use when needing to prompt the user if he wants
+ * to continue.
+ * @param noToolHandler
+ * The handler to use when needing to inform the user, that no
+ * tool is configured.
+ * @return the optioanl result of executing the tool if it was executed
+ * @throws ToolException
+ * when the tool fails
+ */
+ public Optional<ExecutionResult> compare(FileElement localFile,
+ FileElement remoteFile, Optional<String> toolName,
+ BooleanTriState prompt, boolean gui, BooleanTriState trustExitCode,
+ PromptContinueHandler promptHandler,
+ InformNoToolHandler noToolHandler) throws ToolException {
+
+ String toolNameToUse;
+
+ if (toolName == null) {
+ throw new ToolException(JGitText.get().diffToolNullError);
+ }
+
+ if (toolName.isPresent()) {
+ toolNameToUse = toolName.get();
+ } else {
+ toolNameToUse = getDefaultToolName(gui);
+ }
+
+ if (StringUtils.isEmptyOrNull(toolNameToUse)) {
+ throw new ToolException(JGitText.get().diffToolNotGivenError);
+ }
+
+ boolean doPrompt;
+ if (prompt != BooleanTriState.UNSET) {
+ doPrompt = prompt == BooleanTriState.TRUE;
+ } else {
+ doPrompt = isInteractive();
+ }
+
+ if (doPrompt) {
+ if (!promptHandler.prompt(toolNameToUse)) {
+ return Optional.empty();
+ }
+ }
+
+ boolean trust;
+ if (trustExitCode != BooleanTriState.UNSET) {
+ trust = trustExitCode == BooleanTriState.TRUE;
+ } else {
+ trust = config.isTrustExitCode();
+ }
+
+ ExternalDiffTool tool = getTool(toolNameToUse);
+ if (tool == null) {
+ throw new ToolException(
+ "External diff tool is not defined: " + toolNameToUse); //$NON-NLS-1$
+ }
+
+ return Optional.of(
+ compare(localFile, remoteFile, tool, trust));
+ }
+
+ /**
+ * Compare two versions of a file.
+ *
+ * @param localFile
+ * the local file element
+ * @param remoteFile
+ * the remote file element
+ * @param tool
+ * the selected tool
* @param trustExitCode
* the "trust exit code" option
- * @return the return code from executed tool
+ * @return the execution result from tool
+ * @throws ToolException
*/
- public int compare(String newPath, String oldPath, String newId,
- String oldId, String toolName, BooleanTriState prompt,
- BooleanTriState gui, BooleanTriState trustExitCode) {
- return 0;
+ public ExecutionResult compare(FileElement localFile,
+ FileElement remoteFile, ExternalDiffTool tool,
+ boolean trustExitCode) throws ToolException {
+ try {
+ if (tool == null) {
+ throw new ToolException(JGitText
+ .get().diffToolNotSpecifiedInGitAttributesError);
+ }
+ // prepare the command (replace the file paths)
+ String command = ExternalToolUtils.prepareCommand(tool.getCommand(),
+ localFile, remoteFile, null, null);
+ // prepare the environment
+ Map<String, String> env = ExternalToolUtils.prepareEnvironment(
+ gitDir, localFile, remoteFile, null, null);
+ // execute the tool
+ CommandExecutor cmdExec = new CommandExecutor(fs, trustExitCode);
+ return cmdExec.run(command, workTree, env);
+ } catch (IOException | InterruptedException e) {
+ throw new ToolException(e);
+ } finally {
+ localFile.cleanTemporaries();
+ remoteFile.cleanTemporaries();
+ }
}
/**
- * @return the tool names
+ * Get user defined tool names.
+ *
+ * @return the user defined tool names
*/
- public Set<String> getToolNames() {
- return config.getToolNames();
+ public Set<String> getUserDefinedToolNames() {
+ return userDefinedTools.keySet();
}
/**
+ * Get predefined tool names.
+ *
+ * @return the predefined tool names
+ */
+ public Set<String> getPredefinedToolNames() {
+ return predefinedTools.keySet();
+ }
+
+ /**
+ * Get all tool names.
+ *
+ * @return the all tool names (default or available tool name is the first
+ * in the set)
+ */
+ public Set<String> getAllToolNames() {
+ String defaultName = getDefaultToolName(false);
+ if (defaultName == null) {
+ defaultName = getFirstAvailableTool();
+ }
+ return ExternalToolUtils.createSortedToolSet(defaultName,
+ getUserDefinedToolNames(), getPredefinedToolNames());
+ }
+
+ /**
+ * Provides {@link Optional} with the name of an external diff tool if
+ * specified in git configuration for a path.
+ *
+ * The formed git configuration results from global rules as well as merged
+ * rules from info and worktree attributes.
+ *
+ * Triggers {@link TreeWalk} until specified path found in the tree.
+ *
+ * @param path
+ * path to the node in repository to parse git attributes for
+ * @return name of the difftool if set
+ * @throws ToolException
+ */
+ public Optional<String> getExternalToolFromAttributes(final String path)
+ throws ToolException {
+ return ExternalToolUtils.getExternalToolFromAttributes(repo, path,
+ ExternalToolUtils.KEY_DIFF_TOOL);
+ }
+
+ /**
+ * Checks the availability of the predefined tools in the system.
+ *
+ * @return set of predefined available tools
+ */
+ public Set<String> getPredefinedAvailableTools() {
+ Map<String, ExternalDiffTool> defTools = getPredefinedTools(true);
+ Set<String> availableTools = new LinkedHashSet<>();
+ for (Entry<String, ExternalDiffTool> elem : defTools.entrySet()) {
+ if (elem.getValue().isAvailable()) {
+ availableTools.add(elem.getKey());
+ }
+ }
+ return availableTools;
+ }
+
+ /**
+ * Get user defined tools map.
+ *
* @return the user defined tools
*/
public Map<String, ExternalDiffTool> getUserDefinedTools() {
@@ -83,61 +277,106 @@ public class DiffTools {
}
/**
- * @return the available predefined tools
+ * Get predefined tools map.
+ *
+ * @param checkAvailability
+ * true: for checking if tools can be executed; ATTENTION: this
+ * check took some time, do not execute often (store the map for
+ * other actions); false: availability is NOT checked:
+ * isAvailable() returns default false is this case!
+ * @return the predefined tools with optionally checked availability (long
+ * running operation)
*/
- public Map<String, ExternalDiffTool> getAvailableTools() {
+ public Map<String, ExternalDiffTool> getPredefinedTools(
+ boolean checkAvailability) {
+ if (checkAvailability) {
+ for (ExternalDiffTool tool : predefinedTools.values()) {
+ PreDefinedDiffTool predefTool = (PreDefinedDiffTool) tool;
+ predefTool.setAvailable(ExternalToolUtils.isToolAvailable(fs,
+ gitDir, workTree, predefTool.getPath()));
+ }
+ }
return Collections.unmodifiableMap(predefinedTools);
}
/**
- * @return the NOT available predefined tools
+ * Get first available tool name.
+ *
+ * @return the name of first available predefined tool or null
*/
- public Map<String, ExternalDiffTool> getNotAvailableTools() {
- return Collections.unmodifiableMap(new TreeMap<>());
+ public String getFirstAvailableTool() {
+ for (ExternalDiffTool tool : predefinedTools.values()) {
+ if (ExternalToolUtils.isToolAvailable(fs, gitDir, workTree,
+ tool.getPath())) {
+ return tool.getName();
+ }
+ }
+ return null;
}
/**
+ * Get default (gui-)tool name.
+ *
* @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$
+ public String getDefaultToolName(boolean gui) {
+ String guiToolName;
+ if (gui) {
+ guiToolName = config.getDefaultGuiToolName();
+ if (guiToolName != null) {
+ return guiToolName;
+ }
+ }
+ return config.getDefaultToolName();
}
/**
+ * Is interactive diff (prompt enabled) ?
+ *
* @return is interactive (config prompt enabled) ?
*/
public boolean isInteractive() {
- return false;
+ return config.isPrompt();
+ }
+
+ private ExternalDiffTool getTool(final String name) {
+ ExternalDiffTool tool = userDefinedTools.get(name);
+ if (tool == null) {
+ tool = predefinedTools.get(name);
+ }
+ return tool;
}
- private void setupPredefinedTools() {
- predefinedTools = new TreeMap<>();
+ private static Map<String, ExternalDiffTool> setupPredefinedTools() {
+ Map<String, ExternalDiffTool> tools = new TreeMap<>();
for (CommandLineDiffTool tool : CommandLineDiffTool.values()) {
- predefinedTools.put(tool.name(), new PreDefinedDiffTool(tool));
+ tools.put(tool.name(), new PreDefinedDiffTool(tool));
}
+ return tools;
}
- private void setupUserDefinedTools() {
- userDefinedTools = new TreeMap<>();
+ private Map<String, ExternalDiffTool> setupUserDefinedTools(
+ Map<String, ExternalDiffTool> predefTools) {
+ Map<String, ExternalDiffTool> tools = 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);
+ tools.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
+ PreDefinedDiffTool predefTool = (PreDefinedDiffTool) predefTools
.get(name);
if (predefTool != null) {
predefTool.setPath(userTool.getPath());
}
}
}
+ return tools;
}
}
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
index f2d7e828cb..e01b892a53 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalDiffTool.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalDiffTool.java
@@ -30,4 +30,10 @@ public interface ExternalDiffTool {
*/
String getCommand();
+ /**
+ * @return availability of the tool: true if tool can be executed and false
+ * if not
+ */
+ boolean isAvailable();
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java
new file mode 100644
index 0000000000..0c3ddf9afe
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018-2022, 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 org.eclipse.jgit.lib.internal.BooleanTriState;
+
+/**
+ * The merge tool interface.
+ */
+public interface ExternalMergeTool extends ExternalDiffTool {
+
+ /**
+ * @return the tool "trust exit code" option
+ */
+ BooleanTriState getTrustExitCode();
+
+ /**
+ * @param withBase
+ * get command with base present (true) or without base present
+ * (false)
+ * @return the tool command
+ */
+ String getCommand(boolean withBase);
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java
new file mode 100644
index 0000000000..b2dd846d70
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java
@@ -0,0 +1,242 @@
+/*
+ * 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.io.File;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.filter.NotIgnoredFilter;
+import org.eclipse.jgit.util.FS;
+
+/**
+ * Utilities for diff- and merge-tools.
+ */
+public class ExternalToolUtils {
+
+ /**
+ * Key for merge tool git configuration section
+ */
+ public static final String KEY_MERGE_TOOL = "mergetool"; //$NON-NLS-1$
+
+ /**
+ * Key for diff tool git configuration section
+ */
+ public static final String KEY_DIFF_TOOL = "difftool"; //$NON-NLS-1$
+
+ /**
+ * Prepare command for execution.
+ *
+ * @param command
+ * the input "command" string
+ * @param localFile
+ * the local file (ours)
+ * @param remoteFile
+ * the remote file (theirs)
+ * @param mergedFile
+ * the merged file (worktree)
+ * @param baseFile
+ * the base file (can be null)
+ * @return the prepared (with replaced variables) command string
+ * @throws IOException
+ */
+ public static String prepareCommand(String command, FileElement localFile,
+ FileElement remoteFile, FileElement mergedFile,
+ FileElement baseFile) throws IOException {
+ if (localFile != null) {
+ command = localFile.replaceVariable(command);
+ }
+ if (remoteFile != null) {
+ command = remoteFile.replaceVariable(command);
+ }
+ if (mergedFile != null) {
+ command = mergedFile.replaceVariable(command);
+ }
+ if (baseFile != null) {
+ command = baseFile.replaceVariable(command);
+ }
+ return command;
+ }
+
+ /**
+ * Prepare environment needed for execution.
+ *
+ * @param gitDir
+ * the .git directory
+ * @param localFile
+ * the local file (ours)
+ * @param remoteFile
+ * the remote file (theirs)
+ * @param mergedFile
+ * the merged file (worktree)
+ * @param baseFile
+ * the base file (can be null)
+ * @return the environment map with variables and values (file paths)
+ * @throws IOException
+ */
+ public static Map<String, String> prepareEnvironment(File gitDir,
+ FileElement localFile, FileElement remoteFile,
+ FileElement mergedFile, FileElement baseFile) throws IOException {
+ Map<String, String> env = new TreeMap<>();
+ if (gitDir != null) {
+ env.put(Constants.GIT_DIR_KEY, gitDir.getAbsolutePath());
+ }
+ if (localFile != null) {
+ localFile.addToEnv(env);
+ }
+ if (remoteFile != null) {
+ remoteFile.addToEnv(env);
+ }
+ if (mergedFile != null) {
+ mergedFile.addToEnv(env);
+ }
+ if (baseFile != null) {
+ baseFile.addToEnv(env);
+ }
+ return env;
+ }
+
+ /**
+ * @param path
+ * the path to be quoted
+ * @return quoted path if it contains spaces
+ */
+ @SuppressWarnings("nls")
+ public static String quotePath(String path) {
+ // handling of spaces in path
+ if (path.contains(" ")) {
+ // add quotes before if needed
+ if (!path.startsWith("\"")) {
+ path = "\"" + path;
+ }
+ // add quotes after if needed
+ if (!path.endsWith("\"")) {
+ path = path + "\"";
+ }
+ }
+ return path;
+ }
+
+ /**
+ * @param fs
+ * the file system abstraction
+ * @param gitDir
+ * the .git directory
+ * @param directory
+ * the working directory
+ * @param path
+ * the tool path
+ * @return true if tool available and false otherwise
+ */
+ public static boolean isToolAvailable(FS fs, File gitDir, File directory,
+ String path) {
+ boolean available = true;
+ try {
+ CommandExecutor cmdExec = new CommandExecutor(fs, false);
+ available = cmdExec.checkExecutable(path, directory,
+ prepareEnvironment(gitDir, null, null, null, null));
+ } catch (Exception e) {
+ available = false;
+ }
+ return available;
+ }
+
+ /**
+ * @param defaultName
+ * the default tool name
+ * @param userDefinedNames
+ * the user defined tool names
+ * @param preDefinedNames
+ * the pre defined tool names
+ * @return the sorted tool names set: first element is default tool name if
+ * valid, then user defined tool names and then pre defined tool
+ * names
+ */
+ public static Set<String> createSortedToolSet(String defaultName,
+ Set<String> userDefinedNames, Set<String> preDefinedNames) {
+ Set<String> names = new LinkedHashSet<>();
+ if (defaultName != null) {
+ // remove defaultName from both sets
+ Set<String> namesPredef = new LinkedHashSet<>();
+ Set<String> namesUser = new LinkedHashSet<>();
+ namesUser.addAll(userDefinedNames);
+ namesUser.remove(defaultName);
+ namesPredef.addAll(preDefinedNames);
+ namesPredef.remove(defaultName);
+ // add defaultName as first in set
+ names.add(defaultName);
+ names.addAll(namesUser);
+ names.addAll(namesPredef);
+ } else {
+ names.addAll(userDefinedNames);
+ names.addAll(preDefinedNames);
+ }
+ return names;
+ }
+
+ /**
+ * Provides {@link Optional} with the name of an external tool if specified
+ * in git configuration for a path.
+ *
+ * The formed git configuration results from global rules as well as merged
+ * rules from info and worktree attributes.
+ *
+ * Triggers {@link TreeWalk} until specified path found in the tree.
+ *
+ * @param repository
+ * target repository to traverse into
+ * @param path
+ * path to the node in repository to parse git attributes for
+ * @param toolKey
+ * config key name for the tool
+ * @return attribute value for the given tool key if set
+ * @throws ToolException
+ */
+ public static Optional<String> getExternalToolFromAttributes(
+ final Repository repository, final String path,
+ final String toolKey) throws ToolException {
+ try {
+ WorkingTreeIterator treeIterator = new FileTreeIterator(repository);
+ try (TreeWalk walk = new TreeWalk(repository)) {
+ walk.addTree(treeIterator);
+ walk.setFilter(new NotIgnoredFilter(0));
+ while (walk.next()) {
+ String treePath = walk.getPathString();
+ if (treePath.equals(path)) {
+ Attributes attrs = walk.getAttributes();
+ if (attrs.containsKey(toolKey)) {
+ return Optional.of(attrs.getValue(toolKey));
+ }
+ }
+ if (walk.isSubtree()) {
+ walk.enterSubtree();
+ }
+ }
+ // no external tool specified
+ return Optional.empty();
+ }
+
+ } catch (RevisionSyntaxException | IOException e) {
+ throw new ToolException(e);
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java
new file mode 100644
index 0000000000..ba8ca54c58
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java
@@ -0,0 +1,262 @@
+/*
+ * 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.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.eclipse.jgit.diff.DiffEntry;
+
+/**
+ * The element used as left or right file for compare.
+ *
+ */
+public class FileElement {
+
+ /**
+ * The file element type.
+ *
+ */
+ public enum Type {
+ /**
+ * The local file element (ours).
+ */
+ LOCAL,
+ /**
+ * The remote file element (theirs).
+ */
+ REMOTE,
+ /**
+ * The merged file element (path in worktree).
+ */
+ MERGED,
+ /**
+ * The base file element (of ours and theirs).
+ */
+ BASE,
+ /**
+ * The backup file element (copy of merged / conflicted).
+ */
+ BACKUP
+ }
+
+ private final String path;
+
+ private final Type type;
+
+ private final File workDir;
+
+ private InputStream stream;
+
+ private File tempFile;
+
+ /**
+ * Creates file element for path.
+ *
+ * @param path
+ * the file path
+ * @param type
+ * the element type
+ */
+ public FileElement(String path, Type type) {
+ this(path, type, null);
+ }
+
+ /**
+ * Creates file element for path.
+ *
+ * @param path
+ * the file path
+ * @param type
+ * the element type
+ * @param workDir
+ * the working directory of the path (can be null, then current
+ * working dir is used)
+ */
+ public FileElement(String path, Type type, File workDir) {
+ this(path, type, workDir, null);
+ }
+
+ /**
+ * @param path
+ * the file path
+ * @param type
+ * the element type
+ * @param workDir
+ * the working directory of the path (can be null, then current
+ * working dir is used)
+ * @param stream
+ * the object stream to load and write on demand, @see getFile(),
+ * to tempFile once (can be null)
+ */
+ public FileElement(String path, Type type, File workDir,
+ InputStream stream) {
+ this.path = path;
+ this.type = type;
+ this.workDir = workDir;
+ this.stream = stream;
+ }
+
+ /**
+ * @return the file path
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return the element type
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Return
+ * <ul>
+ * <li>a temporary file if already created and stream is not valid</li>
+ * <li>OR a real file from work tree: if no temp file was created (@see
+ * createTempFile()) and if no stream was set</li>
+ * <li>OR an empty temporary file if path is "/dev/null"</li>
+ * <li>OR a temporary file with stream content if stream is valid (not
+ * null); stream is closed and invalidated (set to null) after write to temp
+ * file, so stream is used only once during first call!</li>
+ * </ul>
+ *
+ * @return the object stream
+ * @throws IOException
+ */
+ public File getFile() throws IOException {
+ // if we have already temp file and no stream
+ // then just return this temp file (it was filled from outside)
+ if ((tempFile != null) && (stream == null)) {
+ return tempFile;
+ }
+ File file = new File(workDir, path);
+ // if we have a stream or file is missing (path is "/dev/null")
+ // then optionally create temporary file and fill it with stream content
+ if ((stream != null) || isNullPath()) {
+ if (tempFile == null) {
+ tempFile = getTempFile(file, type.name(), null);
+ }
+ if (stream != null) {
+ copyFromStream(tempFile, stream);
+ }
+ // invalidate the stream, because it is used once
+ stream = null;
+ return tempFile;
+ }
+ return file;
+ }
+
+ /**
+ * Check if path id "/dev/null"
+ *
+ * @return true if path is "/dev/null"
+ */
+ public boolean isNullPath() {
+ return path.equals(DiffEntry.DEV_NULL);
+ }
+
+ /**
+ * Create temporary file in given or system temporary directory.
+ *
+ * @param directory
+ * the directory for the file (can be null); if null system
+ * temporary directory is used
+ * @return temporary file in directory or in the system temporary directory
+ * @throws IOException
+ */
+ public File createTempFile(File directory) throws IOException {
+ if (tempFile == null) {
+ tempFile = getTempFile(new File(path), type.name(), directory);
+ }
+ return tempFile;
+ }
+
+ /**
+ * Delete and invalidate temporary file if necessary.
+ */
+ public void cleanTemporaries() {
+ if (tempFile != null && tempFile.exists()) {
+ tempFile.delete();
+ }
+ tempFile = null;
+ }
+
+ /**
+ * Replace variable in input.
+ *
+ * @param input
+ * the input string
+ * @return the replaced input string
+ * @throws IOException
+ */
+ public String replaceVariable(String input) throws IOException {
+ return input.replace("$" + type.name(), getFile().getPath()); //$NON-NLS-1$
+ }
+
+ /**
+ * Add variable to environment map.
+ *
+ * @param env
+ * the environment where this element should be added
+ * @throws IOException
+ */
+ public void addToEnv(Map<String, String> env) throws IOException {
+ env.put(type.name(), getFile().getPath());
+ }
+
+ private static File getTempFile(final File file, final String midName,
+ final File workingDir) throws IOException {
+ String[] fileNameAndExtension = splitBaseFileNameAndExtension(file);
+ // TODO: avoid long random file name (number generated by
+ // createTempFile)
+ return File.createTempFile(
+ fileNameAndExtension[0] + "_" + midName + "_", //$NON-NLS-1$ //$NON-NLS-2$
+ fileNameAndExtension[1], workingDir);
+ }
+
+ private static void copyFromStream(final File file,
+ final InputStream stream)
+ throws IOException, FileNotFoundException {
+ try (OutputStream outStream = new FileOutputStream(file)) {
+ int read = 0;
+ byte[] bytes = new byte[8 * 1024];
+ while ((read = stream.read(bytes)) != -1) {
+ outStream.write(bytes, 0, read);
+ }
+ } finally {
+ // stream can only be consumed once --> close it and invalidate
+ stream.close();
+ }
+ }
+
+ private static String[] splitBaseFileNameAndExtension(File file) {
+ String[] result = new String[2];
+ result[0] = file.getName();
+ result[1] = ""; //$NON-NLS-1$
+ int idx = result[0].lastIndexOf("."); //$NON-NLS-1$
+ // if "." was found (>-1) and last-index is not first char (>0), then
+ // split (same behavior like cgit)
+ if (idx > 0) {
+ result[1] = result[0].substring(idx, result[0].length());
+ result[0] = result[0].substring(0, idx);
+ }
+ return result;
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/InformNoToolHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/InformNoToolHandler.java
new file mode 100644
index 0000000000..36b290d37d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/InformNoToolHandler.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018-2019, Tim Neumann <Tim.Neumann@advantest.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.List;
+
+/**
+ * A handler for when the diff/merge tool manager wants to inform the user that
+ * no tool has been configured and one of the default tools will be used.
+ */
+public interface InformNoToolHandler {
+ /**
+ * Inform the user, that no tool is configured and that one of the given
+ * tools is used.
+ *
+ * @param toolNames
+ * The tools which are tried
+ */
+ void inform(List<String> toolNames);
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java
new file mode 100644
index 0000000000..9625d5f101
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018-2022, 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_KEY_CMD;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_KEEP_BACKUP;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_KEEP_TEMPORARIES;
+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 static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WRITE_TO_TEMP;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGETOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION;
+
+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 merge tool related configuration options.
+ */
+public class MergeToolConfig {
+
+ /** Key for {@link Config#get(SectionParser)}. */
+ public static final Config.SectionParser<MergeToolConfig> KEY = MergeToolConfig::new;
+
+ private final String toolName;
+
+ private final String guiToolName;
+
+ private final boolean prompt;
+
+ private final boolean keepBackup;
+
+ private final boolean keepTemporaries;
+
+ private final boolean writeToTemp;
+
+ private final Map<String, ExternalMergeTool> tools;
+
+ private MergeToolConfig(Config rc) {
+ toolName = rc.getString(CONFIG_MERGE_SECTION, null, CONFIG_KEY_TOOL);
+ guiToolName = rc.getString(CONFIG_MERGE_SECTION, null,
+ CONFIG_KEY_GUITOOL);
+ prompt = rc.getBoolean(CONFIG_MERGETOOL_SECTION, toolName,
+ CONFIG_KEY_PROMPT, true);
+ keepBackup = rc.getBoolean(CONFIG_MERGETOOL_SECTION,
+ CONFIG_KEY_KEEP_BACKUP, true);
+ keepTemporaries = rc.getBoolean(CONFIG_MERGETOOL_SECTION,
+ CONFIG_KEY_KEEP_TEMPORARIES, false);
+ writeToTemp = rc.getBoolean(CONFIG_MERGETOOL_SECTION,
+ CONFIG_KEY_WRITE_TO_TEMP, false);
+ tools = new HashMap<>();
+ Set<String> subsections = rc.getSubsections(CONFIG_MERGETOOL_SECTION);
+ for (String name : subsections) {
+ String cmd = rc.getString(CONFIG_MERGETOOL_SECTION, name,
+ CONFIG_KEY_CMD);
+ String path = rc.getString(CONFIG_MERGETOOL_SECTION, name,
+ CONFIG_KEY_PATH);
+ BooleanTriState trustExitCode = BooleanTriState.FALSE;
+ String trustStr = rc.getString(CONFIG_MERGETOOL_SECTION, name,
+ CONFIG_KEY_TRUST_EXIT_CODE);
+ if (trustStr != null) {
+ trustExitCode = Boolean.valueOf(trustStr).booleanValue()
+ ? BooleanTriState.TRUE
+ : BooleanTriState.FALSE;
+ } else {
+ trustExitCode = BooleanTriState.UNSET;
+ }
+ if ((cmd != null) || (path != null)) {
+ tools.put(name, new UserDefinedMergeTool(name, path, cmd,
+ trustExitCode));
+ }
+ }
+ }
+
+ /**
+ * @return the default merge tool name (merge.tool)
+ */
+ public String getDefaultToolName() {
+ return toolName;
+ }
+
+ /**
+ * @return the default GUI merge tool name (merge.guitool)
+ */
+ public String getDefaultGuiToolName() {
+ return guiToolName;
+ }
+
+ /**
+ * @return the merge tool "prompt" option (mergetool.prompt)
+ */
+ public boolean isPrompt() {
+ return prompt;
+ }
+
+ /**
+ * @return the tool "keep backup" option
+ */
+ public boolean isKeepBackup() {
+ return keepBackup;
+ }
+
+ /**
+ * @return the tool "keepTemporaries" option
+ */
+ public boolean isKeepTemporaries() {
+ return keepTemporaries;
+ }
+
+ /**
+ * @return the tool "write to temp" option
+ */
+ public boolean isWriteToTemp() {
+ return writeToTemp;
+ }
+
+ /**
+ * @return the tools map
+ */
+ public Map<String, ExternalMergeTool> 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/MergeTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java
new file mode 100644
index 0000000000..b903201264
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com>
+ * Copyright (C) 2019, Tim Neumann <tim.neumann@advantest.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.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.diffmergetool.FileElement.Type;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.StringUtils;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+
+/**
+ * Manages merge tools.
+ */
+public class MergeTools {
+
+ private final FS fs;
+
+ private final File gitDir;
+
+ private final File workTree;
+
+ private final MergeToolConfig config;
+
+ private final Repository repo;
+
+ private final Map<String, ExternalMergeTool> predefinedTools;
+
+ private final Map<String, ExternalMergeTool> userDefinedTools;
+
+ /**
+ * Creates the external merge-tools manager for given repository.
+ *
+ * @param repo
+ * the repository
+ */
+ public MergeTools(Repository repo) {
+ this(repo, repo.getConfig());
+ }
+
+ /**
+ * Creates the external diff-tools manager for given configuration.
+ *
+ * @param config
+ * the git configuration
+ */
+ public MergeTools(StoredConfig config) {
+ this(null, config);
+ }
+
+ private MergeTools(Repository repo, StoredConfig config) {
+ this.repo = repo;
+ this.config = config.get(MergeToolConfig.KEY);
+ this.gitDir = repo == null ? null : repo.getDirectory();
+ this.fs = repo == null ? FS.DETECTED : repo.getFS();
+ this.workTree = repo == null ? null : repo.getWorkTree();
+ predefinedTools = setupPredefinedTools();
+ userDefinedTools = setupUserDefinedTools(predefinedTools);
+ }
+
+ /**
+ * Merge two versions of a file with optional base file.
+ *
+ * @param localFile
+ * The local/left version of the file.
+ * @param remoteFile
+ * The remote/right version of the file.
+ * @param mergedFile
+ * The file for the result.
+ * @param baseFile
+ * The base version of the file. May be null.
+ * @param tempDir
+ * The tmepDir used for the files. May be null.
+ * @param toolName
+ * Optionally the name of the tool to use. If not given the
+ * default tool will be used.
+ * @param prompt
+ * Optionally a flag whether to prompt the user before compare.
+ * If not given the default will be used.
+ * @param gui
+ * A flag whether to prefer a gui tool.
+ * @param promptHandler
+ * The handler to use when needing to prompt the user if he wants
+ * to continue.
+ * @param noToolHandler
+ * The handler to use when needing to inform the user, that no
+ * tool is configured.
+ * @return the optional result of executing the tool if it was executed
+ * @throws ToolException
+ * when the tool fails
+ */
+ public Optional<ExecutionResult> merge(FileElement localFile,
+ FileElement remoteFile, FileElement mergedFile,
+ FileElement baseFile, File tempDir, Optional<String> toolName,
+ BooleanTriState prompt, boolean gui,
+ PromptContinueHandler promptHandler,
+ InformNoToolHandler noToolHandler) throws ToolException {
+
+ String toolNameToUse;
+
+ if (toolName == null) {
+ throw new ToolException(JGitText.get().diffToolNullError);
+ }
+
+ if (toolName.isPresent()) {
+ toolNameToUse = toolName.get();
+ } else {
+ toolNameToUse = getDefaultToolName(gui);
+
+ if (StringUtils.isEmptyOrNull(toolNameToUse)) {
+ noToolHandler.inform(new ArrayList<>(predefinedTools.keySet()));
+ toolNameToUse = getFirstAvailableTool();
+ }
+ }
+
+ if (StringUtils.isEmptyOrNull(toolNameToUse)) {
+ throw new ToolException(JGitText.get().diffToolNotGivenError);
+ }
+
+ boolean doPrompt;
+ if (prompt != BooleanTriState.UNSET) {
+ doPrompt = prompt == BooleanTriState.TRUE;
+ } else {
+ doPrompt = isInteractive();
+ }
+
+ if (doPrompt) {
+ if (!promptHandler.prompt(toolNameToUse)) {
+ return Optional.empty();
+ }
+ }
+
+ ExternalMergeTool tool = getTool(toolNameToUse);
+ if (tool == null) {
+ throw new ToolException(
+ "External merge tool is not defined: " + toolNameToUse); //$NON-NLS-1$
+ }
+
+ return Optional.of(merge(localFile, remoteFile, mergedFile, baseFile,
+ tempDir, tool));
+ }
+
+ /**
+ * Merge two versions of a file with optional base file.
+ *
+ * @param localFile
+ * the local file element
+ * @param remoteFile
+ * the remote file element
+ * @param mergedFile
+ * the merged file element
+ * @param baseFile
+ * the base file element (can be null)
+ * @param tempDir
+ * the temporary directory (needed for backup and auto-remove,
+ * can be null)
+ * @param tool
+ * the selected tool
+ * @return the execution result from tool
+ * @throws ToolException
+ */
+ public ExecutionResult merge(FileElement localFile, FileElement remoteFile,
+ FileElement mergedFile, FileElement baseFile, File tempDir,
+ ExternalMergeTool tool) throws ToolException {
+ FileElement backup = null;
+ ExecutionResult result = null;
+ try {
+ // create additional backup file (copy worktree file)
+ backup = createBackupFile(mergedFile,
+ tempDir != null ? tempDir : workTree);
+ // prepare the command (replace the file paths)
+ String command = ExternalToolUtils.prepareCommand(
+ tool.getCommand(baseFile != null), localFile, remoteFile,
+ mergedFile, baseFile);
+ // prepare the environment
+ Map<String, String> env = ExternalToolUtils.prepareEnvironment(
+ gitDir, localFile, remoteFile, mergedFile, baseFile);
+ boolean trust = tool.getTrustExitCode() == BooleanTriState.TRUE;
+ // execute the tool
+ CommandExecutor cmdExec = new CommandExecutor(fs, trust);
+ result = cmdExec.run(command, workTree, env);
+ // keep backup as .orig file
+ if (backup != null) {
+ keepBackupFile(mergedFile.getPath(), backup);
+ }
+ return result;
+ } catch (IOException | InterruptedException e) {
+ throw new ToolException(e);
+ } finally {
+ // always delete backup file (ignore that it was may be already
+ // moved to keep-backup file)
+ if (backup != null) {
+ backup.cleanTemporaries();
+ }
+ // if the tool returns an error and keepTemporaries is set to true,
+ // then these temporary files will be preserved
+ if (!((result == null) && config.isKeepTemporaries())) {
+ // delete the files
+ localFile.cleanTemporaries();
+ remoteFile.cleanTemporaries();
+ if (baseFile != null) {
+ baseFile.cleanTemporaries();
+ }
+ // delete temporary directory if needed
+ if (config.isWriteToTemp() && (tempDir != null)
+ && tempDir.exists()) {
+ tempDir.delete();
+ }
+ }
+ }
+ }
+
+ private FileElement createBackupFile(FileElement from, File toParentDir)
+ throws IOException {
+ FileElement backup = null;
+ Path path = Paths.get(from.getPath());
+ if (Files.exists(path)) {
+ backup = new FileElement(from.getPath(), Type.BACKUP);
+ Files.copy(path, backup.createTempFile(toParentDir).toPath(),
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ return backup;
+ }
+
+ /**
+ * Create temporary directory.
+ *
+ * @return the created temporary directory if (mergetol.writeToTemp == true)
+ * or null if not configured or false.
+ * @throws IOException
+ */
+ public File createTempDirectory() throws IOException {
+ return config.isWriteToTemp()
+ ? Files.createTempDirectory("jgit-mergetool-").toFile() //$NON-NLS-1$
+ : null;
+ }
+
+ /**
+ * Get user defined tool names.
+ *
+ * @return the user defined tool names
+ */
+ public Set<String> getUserDefinedToolNames() {
+ return userDefinedTools.keySet();
+ }
+
+ /**
+ * @return the predefined tool names
+ */
+ public Set<String> getPredefinedToolNames() {
+ return predefinedTools.keySet();
+ }
+
+ /**
+ * Get all tool names.
+ *
+ * @return the all tool names (default or available tool name is the first
+ * in the set)
+ */
+ public Set<String> getAllToolNames() {
+ String defaultName = getDefaultToolName(false);
+ if (defaultName == null) {
+ defaultName = getFirstAvailableTool();
+ }
+ return ExternalToolUtils.createSortedToolSet(defaultName,
+ getUserDefinedToolNames(), getPredefinedToolNames());
+ }
+
+ /**
+ * Provides {@link Optional} with the name of an external merge tool if
+ * specified in git configuration for a path.
+ *
+ * The formed git configuration results from global rules as well as merged
+ * rules from info and worktree attributes.
+ *
+ * Triggers {@link TreeWalk} until specified path found in the tree.
+ *
+ * @param path
+ * path to the node in repository to parse git attributes for
+ * @return name of the difftool if set
+ * @throws ToolException
+ */
+ public Optional<String> getExternalToolFromAttributes(final String path)
+ throws ToolException {
+ return ExternalToolUtils.getExternalToolFromAttributes(repo, path,
+ ExternalToolUtils.KEY_MERGE_TOOL);
+ }
+
+ /**
+ * Checks the availability of the predefined tools in the system.
+ *
+ * @return set of predefined available tools
+ */
+ public Set<String> getPredefinedAvailableTools() {
+ Map<String, ExternalMergeTool> defTools = getPredefinedTools(true);
+ Set<String> availableTools = new LinkedHashSet<>();
+ for (Entry<String, ExternalMergeTool> elem : defTools.entrySet()) {
+ if (elem.getValue().isAvailable()) {
+ availableTools.add(elem.getKey());
+ }
+ }
+ return availableTools;
+ }
+
+ /**
+ * @return the user defined tools
+ */
+ public Map<String, ExternalMergeTool> getUserDefinedTools() {
+ return Collections.unmodifiableMap(userDefinedTools);
+ }
+
+ /**
+ * Get predefined tools map.
+ *
+ * @param checkAvailability
+ * true: for checking if tools can be executed; ATTENTION: this
+ * check took some time, do not execute often (store the map for
+ * other actions); false: availability is NOT checked:
+ * isAvailable() returns default false is this case!
+ * @return the predefined tools with optionally checked availability (long
+ * running operation)
+ */
+ public Map<String, ExternalMergeTool> getPredefinedTools(
+ boolean checkAvailability) {
+ if (checkAvailability) {
+ for (ExternalMergeTool tool : predefinedTools.values()) {
+ PreDefinedMergeTool predefTool = (PreDefinedMergeTool) tool;
+ predefTool.setAvailable(ExternalToolUtils.isToolAvailable(fs,
+ gitDir, workTree, predefTool.getPath()));
+ }
+ }
+ return Collections.unmodifiableMap(predefinedTools);
+ }
+
+ /**
+ * Get first available tool name.
+ *
+ * @return the name of first available predefined tool or null
+ */
+ public String getFirstAvailableTool() {
+ String name = null;
+ for (ExternalMergeTool tool : predefinedTools.values()) {
+ if (ExternalToolUtils.isToolAvailable(fs, gitDir, workTree,
+ tool.getPath())) {
+ name = tool.getName();
+ break;
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Is interactive merge (prompt enabled) ?
+ *
+ * @return is interactive (config prompt enabled) ?
+ */
+ public boolean isInteractive() {
+ return config.isPrompt();
+ }
+
+ /**
+ * Get the default (gui-)tool name.
+ *
+ * @param gui
+ * use the diff.guitool setting ?
+ * @return the default tool name
+ */
+ public String getDefaultToolName(boolean gui) {
+ return gui ? config.getDefaultGuiToolName()
+ : config.getDefaultToolName();
+ }
+
+ private ExternalMergeTool getTool(final String name) {
+ ExternalMergeTool tool = userDefinedTools.get(name);
+ if (tool == null) {
+ tool = predefinedTools.get(name);
+ }
+ return tool;
+ }
+
+ private void keepBackupFile(String mergedFilePath, FileElement backup)
+ throws IOException {
+ if (config.isKeepBackup()) {
+ Path backupPath = backup.getFile().toPath();
+ Files.move(backupPath,
+ backupPath.resolveSibling(
+ Paths.get(mergedFilePath).getFileName() + ".orig"), //$NON-NLS-1$
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+
+ private Map<String, ExternalMergeTool> setupPredefinedTools() {
+ Map<String, ExternalMergeTool> tools = new TreeMap<>();
+ for (CommandLineMergeTool tool : CommandLineMergeTool.values()) {
+ tools.put(tool.name(), new PreDefinedMergeTool(tool));
+ }
+ return tools;
+ }
+
+ private Map<String, ExternalMergeTool> setupUserDefinedTools(
+ Map<String, ExternalMergeTool> predefTools) {
+ Map<String, ExternalMergeTool> tools = new TreeMap<>();
+ Map<String, ExternalMergeTool> userTools = config.getTools();
+ for (String name : userTools.keySet()) {
+ ExternalMergeTool userTool = userTools.get(name);
+ // if mergetool.<name>.cmd is defined we have user defined tool
+ if (userTool.getCommand() != null) {
+ tools.put(name, userTool);
+ } else if (userTool.getPath() != null) {
+ // if mergetool.<name>.path is defined we just overload the path
+ // of predefined tool
+ PreDefinedMergeTool predefTool = (PreDefinedMergeTool) predefTools
+ .get(name);
+ if (predefTool != null) {
+ predefTool.setPath(userTool.getPath());
+ if (userTool.getTrustExitCode() != BooleanTriState.UNSET) {
+ predefTool
+ .setTrustExitCode(userTool.getTrustExitCode());
+ }
+ }
+ }
+ }
+ return tools;
+ }
+
+}
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
index 1c69fb4911..e1169a2d60 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java
@@ -46,17 +46,6 @@ public class PreDefinedDiffTool extends UserDefinedDiffTool {
*/
@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);
}
@@ -67,7 +56,7 @@ public class PreDefinedDiffTool extends UserDefinedDiffTool {
*/
@Override
public String getCommand() {
- return getPath() + " " + super.getCommand(); //$NON-NLS-1$
+ return ExternalToolUtils.quotePath(getPath()) + " " + super.getCommand(); //$NON-NLS-1$
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java
new file mode 100644
index 0000000000..7b28d32820
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018-2022, 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 org.eclipse.jgit.lib.internal.BooleanTriState;
+
+/**
+ * The pre-defined merge tool.
+ */
+public class PreDefinedMergeTool extends UserDefinedMergeTool {
+
+ /**
+ * the tool parameters without base
+ */
+ private final String parametersWithoutBase;
+
+ /**
+ * Creates the pre-defined merge tool
+ *
+ * @param name
+ * the name
+ * @param path
+ * the path
+ * @param parametersWithBase
+ * the tool parameters that are used together with path as
+ * command and "base is present" ($BASE)
+ * @param parametersWithoutBase
+ * the tool parameters that are used together with path as
+ * command and "base is present" ($BASE)
+ * @param trustExitCode
+ * the "trust exit code" option
+ */
+ public PreDefinedMergeTool(String name, String path,
+ String parametersWithBase, String parametersWithoutBase,
+ BooleanTriState trustExitCode) {
+ super(name, path, parametersWithBase, trustExitCode);
+ this.parametersWithoutBase = parametersWithoutBase;
+ }
+
+ /**
+ * Creates the pre-defined merge tool
+ *
+ * @param tool
+ * the command line merge tool
+ *
+ */
+ public PreDefinedMergeTool(CommandLineMergeTool tool) {
+ this(tool.name(), tool.getPath(), tool.getParameters(true),
+ tool.getParameters(false),
+ tool.isExitCodeTrustable() ? BooleanTriState.TRUE
+ : BooleanTriState.FALSE);
+ }
+
+ /**
+ * @param trustExitCode
+ * the "trust exit code" option
+ */
+ @Override
+ public void setTrustExitCode(BooleanTriState trustExitCode) {
+ super.setTrustExitCode(trustExitCode);
+ }
+
+ /**
+ * @return the tool command (with base present)
+ */
+ @Override
+ public String getCommand() {
+ return getCommand(true);
+ }
+
+ /**
+ * @param withBase
+ * get command with base present (true) or without base present
+ * (false)
+ * @return the tool command
+ */
+ @Override
+ public String getCommand(boolean withBase) {
+ return ExternalToolUtils.quotePath(getPath()) + " " //$NON-NLS-1$
+ + (withBase ? super.getCommand() : parametersWithoutBase);
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PromptContinueHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PromptContinueHandler.java
new file mode 100644
index 0000000000..6ad33df2a0
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PromptContinueHandler.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018-2019, Tim Neumann <Tim.Neumann@advantest.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;
+
+/**
+ * A handler for when the diff/merge tool manager wants to prompt the user
+ * whether to continue
+ */
+public interface PromptContinueHandler {
+ /**
+ * Prompt the user whether to continue with the next file by opening a given
+ * tool.
+ *
+ * @param toolName
+ * The name of the tool to open
+ * @return Whether the user wants to continue
+ */
+ boolean prompt(String toolName);
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java
new file mode 100644
index 0000000000..7cc5bb50d9
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java
@@ -0,0 +1,139 @@
+/*
+ * 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 org.eclipse.jgit.util.FS.ExecutionResult;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tool exception for differentiation.
+ *
+ */
+public class ToolException extends Exception {
+
+ private final static Logger LOG = LoggerFactory
+ .getLogger(ToolException.class);
+
+ private final ExecutionResult result;
+
+ private final boolean commandExecutionError;
+
+ /**
+ * the serial version UID
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public ToolException() {
+ this(null, null, false);
+ }
+
+ /**
+ * @param message
+ * the exception message
+ */
+ public ToolException(String message) {
+ this(message, null, false);
+ }
+
+ /**
+ * @param message
+ * the exception message
+ * @param result
+ * the execution result
+ * @param commandExecutionError
+ * is command execution error happened ?
+ */
+ public ToolException(String message, ExecutionResult result,
+ boolean commandExecutionError) {
+ super(message);
+ this.result = result;
+ this.commandExecutionError = commandExecutionError;
+ }
+
+ /**
+ * @param message
+ * the exception message
+ * @param cause
+ * the cause for throw
+ */
+ public ToolException(String message, Throwable cause) {
+ super(message, cause);
+ result = null;
+ commandExecutionError = false;
+ }
+
+ /**
+ * @param cause
+ * the cause for throw
+ */
+ public ToolException(Throwable cause) {
+ super(cause);
+ result = null;
+ commandExecutionError = false;
+ }
+
+ /**
+ * @return true if result is valid, false else
+ */
+ public boolean isResult() {
+ return result != null;
+ }
+
+ /**
+ * @return the execution result
+ */
+ public ExecutionResult getResult() {
+ return result;
+ }
+
+ /**
+ * @return true if command execution error appears, false otherwise
+ */
+ public boolean isCommandExecutionError() {
+ return commandExecutionError;
+ }
+
+ /**
+ * @return the result Stderr
+ */
+ public String getResultStderr() {
+ if (result == null) {
+ return ""; //$NON-NLS-1$
+ }
+ try {
+ return new String(result.getStderr().toByteArray());
+ } catch (Exception e) {
+ LOG.warn("Failed to retrieve standard error output", e); //$NON-NLS-1$
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * @return the result Stdout
+ */
+ public String getResultStdout() {
+ if (result == null) {
+ return ""; //$NON-NLS-1$
+ }
+ try {
+ return new String(result.getStdout().toByteArray());
+ } catch (Exception e) {
+ LOG.warn("Failed to retrieve standard output", e); //$NON-NLS-1$
+ }
+ return ""; //$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
index 012296eb35..eb72d01cdb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java
@@ -15,6 +15,8 @@ package org.eclipse.jgit.internal.diffmergetool;
*/
public class UserDefinedDiffTool implements ExternalDiffTool {
+ private boolean available;
+
/**
* the diff tool name
*/
@@ -99,6 +101,23 @@ public class UserDefinedDiffTool implements ExternalDiffTool {
}
/**
+ * @return availability of the tool: true if tool can be executed and false
+ * if not
+ */
+ @Override
+ public boolean isAvailable() {
+ return available;
+ }
+
+ /**
+ * @param available
+ * true if tool can be found and false if not
+ */
+ public void setAvailable(boolean available) {
+ this.available = available;
+ }
+
+ /**
* Overrides the path for the given tool. Equivalent to setting
* {@code difftool.<tool>.path}.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java
new file mode 100644
index 0000000000..1dd2f0d793
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018-2022, 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 org.eclipse.jgit.lib.internal.BooleanTriState;
+
+/**
+ * The user-defined merge tool.
+ */
+public class UserDefinedMergeTool extends UserDefinedDiffTool
+ implements ExternalMergeTool {
+
+ /**
+ * the merge tool "trust exit code" option
+ */
+ private BooleanTriState trustExitCode;
+
+ /**
+ * Creates the merge tool
+ *
+ * @param name
+ * the name
+ * @param path
+ * the path
+ * @param cmd
+ * the command
+ * @param trustExitCode
+ * the "trust exit code" option
+ */
+ public UserDefinedMergeTool(String name, String path, String cmd,
+ BooleanTriState trustExitCode) {
+ super(name, path, cmd);
+ this.trustExitCode = trustExitCode;
+ }
+ /**
+ * @return the "trust exit code" flag
+ */
+ @Override
+ public BooleanTriState getTrustExitCode() {
+ return trustExitCode;
+ }
+
+ /**
+ * @param trustExitCode
+ * the new "trust exit code" flag
+ */
+ protected void setTrustExitCode(BooleanTriState trustExitCode) {
+ this.trustExitCode = trustExitCode;
+ }
+
+ /**
+ * @param withBase
+ * not used, because user-defined merge tool can only define one
+ * cmd -> it must handle with and without base present (empty)
+ * @return the tool command
+ */
+ @Override
+ public String getCommand(boolean withBase) {
+ return getCommand();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFileSnapshot.java
index 17bd863528..a784af8c3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFileSnapshot.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFileSnapshot.java
@@ -15,6 +15,7 @@ import java.io.RandomAccessFile;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.Equality;
class PackFileSnapshot extends FileSnapshot {
@@ -61,7 +62,8 @@ class PackFileSnapshot extends FileSnapshot {
}
boolean isChecksumChanged(File packFile) {
- return wasChecksumChanged = checksum != MISSING_CHECKSUM
+ return wasChecksumChanged = !Equality.isSameInstance(checksum,
+ MISSING_CHECKSUM)
&& !checksum.equals(readChecksum(packFile));
}
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 07e38147f7..4aa2edff38 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
@@ -28,7 +28,6 @@ import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
@@ -892,38 +891,27 @@ public class RefDirectory extends RefDatabase {
}
private PackedRefList readPackedRefs() throws IOException {
- int maxStaleRetries = 5;
- int retries = 0;
- while (true) {
- final FileSnapshot snapshot = FileSnapshot.save(packedRefsFile);
- final MessageDigest digest = Constants.newMessageDigest();
- try (BufferedReader br = new BufferedReader(new InputStreamReader(
- new DigestInputStream(new FileInputStream(packedRefsFile),
- digest),
- UTF_8))) {
- try {
- return new PackedRefList(parsePackedRefs(br), snapshot,
- ObjectId.fromRaw(digest.digest()));
- } catch (IOException e) {
- if (FileUtils.isStaleFileHandleInCausalChain(e)
- && retries < maxStaleRetries) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(MessageFormat.format(
- JGitText.get().packedRefsHandleIsStale,
- Integer.valueOf(retries)), e);
+ try {
+ PackedRefList result = FileUtils.readWithRetries(packedRefsFile,
+ f -> {
+ FileSnapshot snapshot = FileSnapshot.save(f);
+ MessageDigest digest = Constants.newMessageDigest();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(
+ new DigestInputStream(
+ new FileInputStream(f), digest),
+ UTF_8))) {
+ return new PackedRefList(parsePackedRefs(br),
+ snapshot,
+ ObjectId.fromRaw(digest.digest()));
}
- retries++;
- continue;
- }
- throw e;
- }
- } catch (FileNotFoundException noPackedRefs) {
- if (packedRefsFile.exists()) {
- throw noPackedRefs;
- }
- // Ignore it and leave the new list empty.
- return NO_PACKED_REFS;
- }
+ });
+ return result != null ? result : NO_PACKED_REFS;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(MessageFormat
+ .format(JGitText.get().cannotReadFile, packedRefsFile), e);
}
}
@@ -1090,40 +1078,55 @@ public class RefDirectory extends RefDatabase {
}
final int limit = 4096;
- final byte[] buf;
- FileSnapshot otherSnapshot = FileSnapshot.save(path);
- try {
- buf = IO.readSome(path, limit);
- } catch (FileNotFoundException noFile) {
- if (path.isFile()) {
- throw noFile;
+
+ class LooseItems {
+ final FileSnapshot snapshot;
+
+ final byte[] buf;
+
+ LooseItems(FileSnapshot snapshot, byte[] buf) {
+ this.snapshot = snapshot;
+ this.buf = buf;
}
- return null; // doesn't exist or no file; not a reference.
}
-
- int n = buf.length;
+ LooseItems loose = null;
+ try {
+ loose = FileUtils.readWithRetries(path,
+ f -> new LooseItems(FileSnapshot.save(f),
+ IO.readSome(f, limit)));
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(
+ MessageFormat.format(JGitText.get().cannotReadFile, path),
+ e);
+ }
+ if (loose == null) {
+ return null;
+ }
+ int n = loose.buf.length;
if (n == 0)
return null; // empty file; not a reference.
- if (isSymRef(buf, n)) {
+ if (isSymRef(loose.buf, n)) {
if (n == limit)
return null; // possibly truncated ref
// trim trailing whitespace
- while (0 < n && Character.isWhitespace(buf[n - 1]))
+ while (0 < n && Character.isWhitespace(loose.buf[n - 1]))
n--;
if (n < 6) {
- String content = RawParseUtils.decode(buf, 0, n);
+ String content = RawParseUtils.decode(loose.buf, 0, n);
throw new IOException(MessageFormat.format(JGitText.get().notARef, name, content));
}
- final String target = RawParseUtils.decode(buf, 5, n);
+ final String target = RawParseUtils.decode(loose.buf, 5, n);
if (ref != null && ref.isSymbolic()
&& ref.getTarget().getName().equals(target)) {
assert(currentSnapshot != null);
- currentSnapshot.setClean(otherSnapshot);
+ currentSnapshot.setClean(loose.snapshot);
return ref;
}
- return newSymbolicRef(otherSnapshot, name, target);
+ return newSymbolicRef(loose.snapshot, name, target);
}
if (n < OBJECT_ID_STRING_LENGTH)
@@ -1131,23 +1134,23 @@ public class RefDirectory extends RefDatabase {
final ObjectId id;
try {
- id = ObjectId.fromString(buf, 0);
+ id = ObjectId.fromString(loose.buf, 0);
if (ref != null && !ref.isSymbolic()
&& id.equals(ref.getTarget().getObjectId())) {
assert(currentSnapshot != null);
- currentSnapshot.setClean(otherSnapshot);
+ currentSnapshot.setClean(loose.snapshot);
return ref;
}
} catch (IllegalArgumentException notRef) {
- while (0 < n && Character.isWhitespace(buf[n - 1]))
+ while (0 < n && Character.isWhitespace(loose.buf[n - 1]))
n--;
- String content = RawParseUtils.decode(buf, 0, n);
+ String content = RawParseUtils.decode(loose.buf, 0, n);
throw new IOException(MessageFormat.format(JGitText.get().notARef,
name, content), notRef);
}
- return new LooseUnpeeled(otherSnapshot, name, id);
+ return new LooseUnpeeled(loose.snapshot, name, id);
}
private static boolean isSymRef(byte[] buf, int n) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BaseSearch.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BaseSearch.java
index 1c24aff12d..cda456c3cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BaseSearch.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/BaseSearch.java
@@ -142,6 +142,7 @@ class BaseSearch {
return ptr;
}
+ @SuppressWarnings("ReferenceEquality")
private void add(AnyObjectId id, int objectType, int pathHash) {
ObjectToPack obj = new ObjectToPack(id, objectType);
obj.setEdge();
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 55cc02683a..6a9b45b065 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Julian Ruppel <julian.ruppel@sap.com>
+ * Copyright (c) 2020, 2022 Julian Ruppel <julian.ruppel@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
@@ -29,6 +29,7 @@ import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.StringUtils;
/**
* The standard "commit" configuration parameters.
@@ -44,6 +45,9 @@ public class CommitConfig {
private static final String CUT = " ------------------------ >8 ------------------------\n"; //$NON-NLS-1$
+ private static final char[] COMMENT_CHARS = { '#', ';', '@', '!', '$', '%',
+ '^', '&', '|', ':' };
+
/**
* How to clean up commit messages when committing.
*
@@ -99,6 +103,10 @@ public class CommitConfig {
private CleanupMode cleanupMode;
+ private char commentCharacter = '#';
+
+ private boolean autoCommentChar = false;
+
private CommitConfig(Config rc) {
commitTemplatePath = rc.getString(ConfigConstants.CONFIG_COMMIT_SECTION,
null, ConfigConstants.CONFIG_KEY_COMMIT_TEMPLATE);
@@ -106,6 +114,18 @@ public class CommitConfig {
null, ConfigConstants.CONFIG_KEY_COMMIT_ENCODING);
cleanupMode = rc.getEnum(ConfigConstants.CONFIG_COMMIT_SECTION, null,
ConfigConstants.CONFIG_KEY_CLEANUP, CleanupMode.DEFAULT);
+ String comment = rc.getString(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_COMMENT_CHAR);
+ if (!StringUtils.isEmptyOrNull(comment)) {
+ if ("auto".equalsIgnoreCase(comment)) { //$NON-NLS-1$
+ autoCommentChar = true;
+ } else {
+ char first = comment.charAt(0);
+ if (first > ' ' && first < 127) {
+ commentCharacter = first;
+ }
+ }
+ }
}
/**
@@ -131,6 +151,51 @@ public class CommitConfig {
}
/**
+ * Retrieves the comment character set by git config
+ * {@code core.commentChar}.
+ *
+ * @return the character to use for comments in commit messages
+ * @since 6.2
+ */
+ public char getCommentChar() {
+ return commentCharacter;
+ }
+
+ /**
+ * Determines the comment character to use for a particular text. If
+ * {@code core.commentChar} is "auto", tries to determine an unused
+ * character; if none is found, falls back to '#'. Otherwise returns the
+ * character given by {@code core.commentChar}.
+ *
+ * @param text
+ * existing text
+ *
+ * @return the character to use
+ * @since 6.2
+ */
+ public char getCommentChar(String text) {
+ if (isAutoCommentChar()) {
+ char toUse = determineCommentChar(text);
+ if (toUse > 0) {
+ return toUse;
+ }
+ return '#';
+ }
+ return getCommentChar();
+ }
+
+ /**
+ * Tells whether the comment character should be determined by choosing a
+ * character not occurring in a commit message.
+ *
+ * @return {@code true} if git config {@code core.commentChar} is "auto"
+ * @since 6.2
+ */
+ public boolean isAutoCommentChar() {
+ return autoCommentChar;
+ }
+
+ /**
* Retrieves the {@link CleanupMode} as given by git config
* {@code commit.cleanup}.
*
@@ -315,4 +380,41 @@ public class CommitConfig {
}
return false;
}
+
+ /**
+ * Determines a comment character by choosing one from a limited set of
+ * 7-bit ASCII characters that do not occur in the given text at the
+ * beginning of any line. If none can be determined, {@code (char) 0} is
+ * returned.
+ *
+ * @param text
+ * to get a comment character for
+ * @return the comment character, or {@code (char) 0} if none could be
+ * determined
+ * @since 6.2
+ */
+ public static char determineCommentChar(String text) {
+ if (StringUtils.isEmptyOrNull(text)) {
+ return '#';
+ }
+ final boolean[] inUse = new boolean[127];
+ for (String line : text.split("\n")) { //$NON-NLS-1$
+ int len = line.length();
+ for (int i = 0; i < len; i++) {
+ char ch = line.charAt(i);
+ if (!Character.isWhitespace(ch)) {
+ if (ch >= 0 && ch < inUse.length) {
+ inUse[ch] = true;
+ }
+ break;
+ }
+ }
+ }
+ for (char candidate : COMMENT_CHARS) {
+ if (!inUse[candidate]) {
+ return candidate;
+ }
+ }
+ return (char) 0;
+ }
} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 80d720ae41..2342cad0d7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -2,7 +2,7 @@
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* Copyright (C) 2012-2013, Robin Rosenberg
- * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> and others
+ * Copyright (C) 2018-2022, 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
@@ -10,6 +10,7 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+
package org.eclipse.jgit.lib;
/**
@@ -31,14 +32,14 @@ public final class ConfigConstants {
public static final String CONFIG_DIFF_SECTION = "diff";
/**
- * The "tool" key within "diff" section
+ * The "tool" key within "diff" or "merge" section
*
* @since 6.1
*/
public static final String CONFIG_KEY_TOOL = "tool";
/**
- * The "guitool" key within "diff" section
+ * The "guitool" key within "diff" or "merge" section
*
* @since 6.1
*/
@@ -52,21 +53,21 @@ public final class ConfigConstants {
public static final String CONFIG_DIFFTOOL_SECTION = "difftool";
/**
- * The "prompt" key within "difftool" section
+ * The "prompt" key within "difftool" or "mergetool" section
*
* @since 6.1
*/
public static final String CONFIG_KEY_PROMPT = "prompt";
/**
- * The "trustExitCode" key within "difftool" section
+ * The "trustExitCode" key within "difftool" or "mergetool.<name>." section
*
* @since 6.1
*/
public static final String CONFIG_KEY_TRUST_EXIT_CODE = "trustExitCode";
/**
- * The "cmd" key within "difftool.*." section
+ * The "cmd" key within "difftool.*." or "mergetool.*." section
*
* @since 6.1
*/
@@ -124,6 +125,34 @@ public final class ConfigConstants {
public static final String CONFIG_MERGE_SECTION = "merge";
/**
+ * The "mergetool" section
+ *
+ * @since 6.2
+ */
+ public static final String CONFIG_MERGETOOL_SECTION = "mergetool";
+
+ /**
+ * The "keepBackup" key within "mergetool" section
+ *
+ * @since 6.2
+ */
+ public static final String CONFIG_KEY_KEEP_BACKUP = "keepBackup";
+
+ /**
+ * The "keepTemporaries" key within "mergetool" section
+ *
+ * @since 6.2
+ */
+ public static final String CONFIG_KEY_KEEP_TEMPORARIES = "keepTemporaries";
+
+ /**
+ * The "writeToTemp" key within "mergetool" section
+ *
+ * @since 6.2
+ */
+ public static final String CONFIG_KEY_WRITE_TO_TEMP = "writeToTemp";
+
+ /**
* The "filter" section
* @since 4.6
*/
@@ -203,6 +232,13 @@ public final class ConfigConstants {
public static final String CONFIG_KEY_FORCE_SIGN_ANNOTATED = "forceSignAnnotated";
/**
+ * The "commentChar" key.
+ *
+ * @since 6.2
+ */
+ public static final String CONFIG_KEY_COMMENT_CHAR = "commentChar";
+
+ /**
* The "hooksPath" key.
*
* @since 5.6
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java
index 4b1dbedeb1..59775c475b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.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
@@ -26,20 +26,41 @@ public abstract class GpgSignatureVerifierFactory {
private static final Logger LOG = LoggerFactory
.getLogger(GpgSignatureVerifierFactory.class);
- private static volatile GpgSignatureVerifierFactory defaultFactory = loadDefault();
+ private static class DefaultFactory {
- private static GpgSignatureVerifierFactory loadDefault() {
- try {
- ServiceLoader<GpgSignatureVerifierFactory> loader = ServiceLoader
- .load(GpgSignatureVerifierFactory.class);
- Iterator<GpgSignatureVerifierFactory> iter = loader.iterator();
- if (iter.hasNext()) {
- return iter.next();
+ private static volatile GpgSignatureVerifierFactory defaultFactory = loadDefault();
+
+ private static GpgSignatureVerifierFactory loadDefault() {
+ try {
+ ServiceLoader<GpgSignatureVerifierFactory> loader = ServiceLoader
+ .load(GpgSignatureVerifierFactory.class);
+ Iterator<GpgSignatureVerifierFactory> iter = loader.iterator();
+ if (iter.hasNext()) {
+ return iter.next();
+ }
+ } catch (ServiceConfigurationError e) {
+ LOG.error(e.getMessage(), e);
}
- } catch (ServiceConfigurationError e) {
- LOG.error(e.getMessage(), e);
+ return null;
+ }
+
+ private DefaultFactory() {
+ // No instantiation
+ }
+
+ public static GpgSignatureVerifierFactory getDefault() {
+ return defaultFactory;
+ }
+
+ /**
+ * Sets the default factory.
+ *
+ * @param factory
+ * the new default factory
+ */
+ public static void setDefault(GpgSignatureVerifierFactory factory) {
+ defaultFactory = factory;
}
- return null;
}
/**
@@ -48,7 +69,7 @@ public abstract class GpgSignatureVerifierFactory {
* @return the default factory or {@code null} if none set
*/
public static GpgSignatureVerifierFactory getDefault() {
- return defaultFactory;
+ return DefaultFactory.getDefault();
}
/**
@@ -58,7 +79,7 @@ public abstract class GpgSignatureVerifierFactory {
* the new default factory
*/
public static void setDefault(GpgSignatureVerifierFactory factory) {
- defaultFactory = factory;
+ DefaultFactory.setDefault(factory);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
index 5b32cf0b5f..b25a61b506 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, Salesforce. and others
+ * Copyright (C) 2018, 2022 Salesforce 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
@@ -26,22 +26,38 @@ import org.slf4j.LoggerFactory;
* @since 5.3
*/
public abstract class GpgSigner {
+
private static final Logger LOG = LoggerFactory.getLogger(GpgSigner.class);
- private static GpgSigner defaultSigner = loadGpgSigner();
+ private static class DefaultSigner {
+
+ private static volatile GpgSigner defaultSigner = loadGpgSigner();
- private static GpgSigner loadGpgSigner() {
- try {
- ServiceLoader<GpgSigner> loader = ServiceLoader
- .load(GpgSigner.class);
- Iterator<GpgSigner> iter = loader.iterator();
- if (iter.hasNext()) {
- return iter.next();
+ private static GpgSigner loadGpgSigner() {
+ try {
+ ServiceLoader<GpgSigner> loader = ServiceLoader
+ .load(GpgSigner.class);
+ Iterator<GpgSigner> iter = loader.iterator();
+ if (iter.hasNext()) {
+ return iter.next();
+ }
+ } catch (ServiceConfigurationError e) {
+ LOG.error(e.getMessage(), e);
}
- } catch (ServiceConfigurationError e) {
- LOG.error(e.getMessage(), e);
+ return null;
+ }
+
+ private DefaultSigner() {
+ // No instantiation
+ }
+
+ public static GpgSigner getDefault() {
+ return defaultSigner;
+ }
+
+ public static void setDefault(GpgSigner signer) {
+ defaultSigner = signer;
}
- return null;
}
/**
@@ -50,7 +66,7 @@ public abstract class GpgSigner {
* @return the default signer, or <code>null</code>.
*/
public static GpgSigner getDefault() {
- return defaultSigner;
+ return DefaultSigner.getDefault();
}
/**
@@ -61,7 +77,7 @@ public abstract class GpgSigner {
* default.
*/
public static void setDefault(GpgSigner signer) {
- GpgSigner.defaultSigner = signer;
+ DefaultSigner.setDefault(signer);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
index 94e7c53adb..c11fca13d8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
@@ -138,6 +138,7 @@ public class PlotCommit<L extends PlotLane> extends RevCommit {
* the commit to test.
* @return true if the given commit built on top of this commit.
*/
+ @SuppressWarnings("ReferenceEquality")
public final boolean isChild(PlotCommit c) {
for (PlotCommit a : children)
if (a == c)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
index 18ea7560fd..458f240982 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
@@ -92,6 +92,7 @@ public class PlotCommitList<L extends PlotLane> extends
}
/** {@inheritDoc} */
+ @SuppressWarnings("ReferenceEquality")
@Override
protected void enter(int index, PlotCommit<L> currCommit) {
setupChildren(currCommit);
@@ -188,6 +189,7 @@ public class PlotCommitList<L extends PlotLane> extends
* may be null if <code>currCommit</code> is the first commit on
* the lane
*/
+ @SuppressWarnings("ReferenceEquality")
private void handleBlockedLanes(final int index, final PlotCommit currCommit,
final PlotCommit childOnLane) {
for (PlotCommit child : currCommit.children) {
@@ -214,6 +216,7 @@ public class PlotCommitList<L extends PlotLane> extends
}
// Handles the case where currCommit is a non-first parent of the child
+ @SuppressWarnings("ReferenceEquality")
private PlotLane handleMerge(final int index, final PlotCommit currCommit,
final PlotCommit childOnLane, PlotCommit child, PlotLane laneToUse) {
@@ -287,6 +290,7 @@ public class PlotCommitList<L extends PlotLane> extends
* @param child
* @param laneToContinue
*/
+ @SuppressWarnings("ReferenceEquality")
private void drawLaneToChild(final int commitIndex, PlotCommit child,
PlotLane laneToContinue) {
for (int r = commitIndex - 1; r >= 0; r--) {
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 a50eaf1a8a..a25948e50b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -143,8 +143,19 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
*/
static final int TOPO_QUEUED = 1 << 6;
+ /**
+ * Set on a RevCommit when a {@link TreeRevFilter} has been applied.
+ * <p>
+ * This flag is processed by the {@link RewriteGenerator} to check if a
+ * {@link TreeRevFilter} has been applied.
+ *
+ * @see TreeRevFilter
+ * @see RewriteGenerator
+ */
+ static final int TREE_REV_FILTER_APPLIED = 1 << 7;
+
/** Number of flag bits we keep internal for our own use. See above flags. */
- static final int RESERVED_FLAGS = 7;
+ static final int RESERVED_FLAGS = 8;
private static final int APP_FLAGS = -1 & ~((1 << RESERVED_FLAGS) - 1);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
index a928c2e79b..1adef07ad9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
@@ -24,14 +24,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
* commit that matched the revision walker's filters.
* <p>
* This generator is the second phase of a path limited revision walk and
- * assumes it is receiving RevCommits from {@link TreeRevFilter},
- * after they have been fully buffered by {@link AbstractRevQueue}. The full
- * buffering is necessary to allow the simple loop used within our own
- * {@link #rewrite(RevCommit)} to pull completely through a strand of
- * {@link RevWalk#REWRITE} colored commits and come up with a simplification
- * that makes the DAG dense. Not fully buffering the commits first would cause
- * this loop to abort early, due to commits not being parsed and colored
- * correctly.
+ * assumes it is receiving RevCommits from {@link TreeRevFilter}.
*
* @see TreeRevFilter
*/
@@ -43,9 +36,12 @@ class RewriteGenerator extends Generator {
private final Generator source;
+ private final FIFORevQueue pending;
+
RewriteGenerator(Generator s) {
super(s.firstParent);
source = s;
+ pending = new FIFORevQueue(s.firstParent);
}
@Override
@@ -58,13 +54,23 @@ class RewriteGenerator extends Generator {
return source.outputType() & ~NEEDS_REWRITE;
}
+ @SuppressWarnings("ReferenceEquality")
@Override
RevCommit next() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
- final RevCommit c = source.next();
+ RevCommit c = pending.next();
+
if (c == null) {
- return null;
+ c = source.next();
+ if (c == null) {
+ // We are done: Both the source generator and our internal list
+ // are completely exhausted.
+ return null;
+ }
}
+
+ applyFilterToParents(c);
+
boolean rewrote = false;
final RevCommit[] pList = c.parents;
final int nParents = pList.length;
@@ -90,10 +96,41 @@ class RewriteGenerator extends Generator {
return c;
}
- private RevCommit rewrite(RevCommit p) {
+ /**
+ * Makes sure that the {@link TreeRevFilter} has been applied to all parents
+ * of this commit by the previous {@link PendingGenerator}.
+ *
+ * @param c
+ * @throws MissingObjectException
+ * @throws IncorrectObjectTypeException
+ * @throws IOException
+ */
+ private void applyFilterToParents(RevCommit c)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ IOException {
+ for (RevCommit parent : c.parents) {
+ while ((parent.flags & RevWalk.TREE_REV_FILTER_APPLIED) == 0) {
+
+ RevCommit n = source.next();
+
+ if (n != null) {
+ pending.add(n);
+ } else {
+ // Source generator is exhausted; filter has been applied to
+ // all commits
+ return;
+ }
+
+ }
+
+ }
+ }
+
+ private RevCommit rewrite(RevCommit p) throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
for (;;) {
- final RevCommit[] pList = p.parents;
- if (pList.length > 1) {
+
+ if (p.parents.length > 1) {
// This parent is a merge, so keep it.
//
return p;
@@ -113,14 +150,16 @@ class RewriteGenerator extends Generator {
return p;
}
- if (pList.length == 0) {
+ if (p.parents.length == 0) {
// We can't go back any further, other than to
// just delete the parent entirely.
//
return null;
}
- p = pList[0];
+ applyFilterToParents(p.parents[0]);
+ p = p.parents[0];
+
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
index bfcea6ea8f..a79901ca10 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
@@ -125,12 +125,6 @@ class StartGenerator extends Generator {
}
if ((g.outputType() & NEEDS_REWRITE) != 0) {
- // Correction for an upstream NEEDS_REWRITE is to buffer
- // fully and then apply a rewrite generator that can
- // pull through the rewrite chain and produce a dense
- // output graph.
- //
- g = new FIFORevQueue(g);
g = new RewriteGenerator(g);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
index 822fc5320c..92d72268d1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java
@@ -41,6 +41,8 @@ public class TreeRevFilter extends RevFilter {
private static final int UNINTERESTING = RevWalk.UNINTERESTING;
+ private static final int FILTER_APPLIED = RevWalk.TREE_REV_FILTER_APPLIED;
+
private final int rewriteFlag;
private final TreeWalk pathFilter;
@@ -101,6 +103,7 @@ public class TreeRevFilter extends RevFilter {
public boolean include(RevWalk walker, RevCommit c)
throws StopWalkException, MissingObjectException,
IncorrectObjectTypeException, IOException {
+ c.flags |= FILTER_APPLIED;
// Reset the tree filter to scan this commit and parents.
//
RevCommit[] pList = c.parents;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index 2443c4e771..cba5e1697c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -20,7 +20,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
@@ -37,15 +36,11 @@ import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The configuration file that is stored in the file of the file system.
*/
public class FileBasedConfig extends StoredConfig {
- private static final Logger LOG = LoggerFactory
- .getLogger(FileBasedConfig.class);
private final File configFile;
@@ -115,16 +110,15 @@ public class FileBasedConfig extends StoredConfig {
*/
@Override
public void load() throws IOException, ConfigInvalidException {
- final int maxRetries = 5;
- int retryDelayMillis = 20;
- int retries = 0;
- while (true) {
- final FileSnapshot oldSnapshot = snapshot;
- final FileSnapshot newSnapshot;
- // don't use config in this snapshot to avoid endless recursion
- newSnapshot = FileSnapshot.saveNoConfig(getFile());
- try {
- final byte[] in = IO.readFully(getFile());
+ try {
+ FileSnapshot[] lastSnapshot = { null };
+ Boolean wasRead = FileUtils.readWithRetries(getFile(), f -> {
+ final FileSnapshot oldSnapshot = snapshot;
+ final FileSnapshot newSnapshot;
+ // don't use config in this snapshot to avoid endless recursion
+ newSnapshot = FileSnapshot.saveNoConfig(f);
+ lastSnapshot[0] = newSnapshot;
+ final byte[] in = IO.readFully(f);
final ObjectId newHash = hash(in);
if (hash.equals(newHash)) {
if (oldSnapshot.equals(newSnapshot)) {
@@ -145,47 +139,17 @@ public class FileBasedConfig extends StoredConfig {
snapshot = newSnapshot;
hash = newHash;
}
- return;
- } catch (FileNotFoundException noFile) {
- // might be locked by another process (see exception Javadoc)
- if (retries < maxRetries && configFile.exists()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(MessageFormat.format(
- JGitText.get().configHandleMayBeLocked,
- Integer.valueOf(retries)), noFile);
- }
- try {
- Thread.sleep(retryDelayMillis);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- retries++;
- retryDelayMillis *= 2; // max wait 1260 ms
- continue;
- }
- if (configFile.exists()) {
- throw noFile;
- }
+ return Boolean.TRUE;
+ });
+ if (wasRead == null) {
clear();
- snapshot = newSnapshot;
- return;
- } catch (IOException e) {
- if (FileUtils.isStaleFileHandle(e)
- && retries < maxRetries) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(MessageFormat.format(
- JGitText.get().configHandleIsStale,
- Integer.valueOf(retries)), e);
- }
- retries++;
- continue;
- }
- throw new IOException(MessageFormat
- .format(JGitText.get().cannotReadFile, getFile()), e);
- } catch (ConfigInvalidException e) {
- throw new ConfigInvalidException(MessageFormat
- .format(JGitText.get().cannotReadFile, getFile()), e);
+ snapshot = lastSnapshot[0];
}
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ConfigInvalidException(MessageFormat
+ .format(JGitText.get().cannotReadFile, getFile()), e);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index f48e1e68cc..3f167ccce2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2008, 2010 Google Inc.
* 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
@@ -1004,9 +1004,12 @@ public abstract class BasePackFetchConnection extends BasePackConnection
OutputStream outputStream) throws IOException {
onReceivePack();
InputStream input = in;
- if (sideband)
- input = new SideBandInputStream(input, monitor, getMessageWriter(),
- outputStream);
+ SideBandInputStream sidebandIn = null;
+ if (sideband) {
+ sidebandIn = new SideBandInputStream(input, monitor,
+ getMessageWriter(), outputStream);
+ input = sidebandIn;
+ }
try (ObjectInserter ins = local.newObjectInserter()) {
PackParser parser = ins.newPackParser(input);
@@ -1015,6 +1018,10 @@ public abstract class BasePackFetchConnection extends BasePackConnection
parser.setLockMessage(lockMessage);
packLock = parser.parse(monitor);
ins.flush();
+ } finally {
+ if (sidebandIn != null) {
+ sidebandIn.drainMessages();
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index b87a85d934..b7be59d6f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
- * 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
@@ -194,10 +194,11 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
// the other data channels.
//
int b = in.read();
- if (0 <= b)
+ if (0 <= b) {
throw new TransportException(uri, MessageFormat.format(
JGitText.get().expectedEOFReceived,
Character.valueOf((char) b)));
+ }
}
}
} catch (TransportException e) {
@@ -205,6 +206,9 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
} catch (Exception e) {
throw new TransportException(uri, e.getMessage(), e);
} finally {
+ if (in instanceof SideBandInputStream) {
+ ((SideBandInputStream) in).drainMessages();
+ }
close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index 7d7b3ee0a0..87e5476036 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -31,6 +31,7 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NotSupportedException;
@@ -56,6 +57,12 @@ class FetchProcess {
/** List of things we want to fetch from the remote repository. */
private final Collection<RefSpec> toFetch;
+ /**
+ * List of things we don't want to fetch from the remote repository or to
+ * the local repository.
+ */
+ private final Collection<RefSpec> negativeRefSpecs;
+
/** Set of refs we will actually wind up asking to obtain. */
private final HashMap<ObjectId, Ref> askFor = new HashMap<>();
@@ -74,9 +81,12 @@ class FetchProcess {
private Map<String, Ref> localRefs;
- FetchProcess(Transport t, Collection<RefSpec> f) {
+ FetchProcess(Transport t, Collection<RefSpec> refSpecs) {
transport = t;
- toFetch = f;
+ toFetch = refSpecs.stream().filter(refSpec -> !refSpec.isNegative())
+ .collect(Collectors.toList());
+ negativeRefSpecs = refSpecs.stream().filter(RefSpec::isNegative)
+ .collect(Collectors.toList());
}
void execute(ProgressMonitor monitor, FetchResult result,
@@ -389,8 +399,13 @@ class FetchProcess {
private void expandWildcard(RefSpec spec, Set<Ref> matched)
throws TransportException {
for (Ref src : conn.getRefs()) {
- if (spec.matchSource(src) && matched.add(src))
- want(src, spec.expandFromSource(src));
+ if (spec.matchSource(src)) {
+ RefSpec expandedRefSpec = spec.expandFromSource(src);
+ if (!matchNegativeRefSpec(expandedRefSpec)
+ && matched.add(src)) {
+ want(src, expandedRefSpec);
+ }
+ }
}
}
@@ -406,11 +421,27 @@ class FetchProcess {
if (src == null) {
throw new TransportException(MessageFormat.format(JGitText.get().remoteDoesNotHaveSpec, want));
}
- if (matched.add(src)) {
+ if (!matchNegativeRefSpec(spec) && matched.add(src)) {
want(src, spec);
}
}
+ private boolean matchNegativeRefSpec(RefSpec spec) {
+ for (RefSpec negativeRefSpec : negativeRefSpecs) {
+ if (negativeRefSpec.getSource() != null && spec.getSource() != null
+ && negativeRefSpec.matchSource(spec.getSource())) {
+ return true;
+ }
+
+ if (negativeRefSpec.getDestination() != null
+ && spec.getDestination() != null && negativeRefSpec
+ .matchDestination(spec.getDestination())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean localHasObject(ObjectId id) throws TransportException {
try {
return transport.local.getObjectDatabase().has(id);
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 942dad46e0..b59ae0c450 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> and others
+ * Copyright (C) 2008, 2022 Marek Zawirski <marek.zawirski@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
@@ -166,6 +166,7 @@ class PushProcess {
if (prePush != null) {
try {
prePush.setRefs(willBeAttempted);
+ prePush.setDryRun(transport.isDryRun());
prePush.call();
} catch (AbortedByHookException | IOException e) {
throw new TransportException(e.getMessage(), e);
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 56d0036a20..e36eeccfb1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
@@ -53,6 +53,9 @@ public class RefSpec implements Serializable {
/** Is this the special ":" RefSpec? */
private boolean matching;
+ /** Is this a negative refspec. */
+ private boolean negative;
+
/**
* How strict to be about wildcards.
*
@@ -96,12 +99,23 @@ public class RefSpec implements Serializable {
wildcard = false;
srcName = Constants.HEAD;
dstName = null;
+ negative =false;
allowMismatchedWildcards = WildcardMode.REQUIRE_MATCH;
}
/**
* Parse a ref specification for use during transport operations.
* <p>
+ * {@link RefSpec}s can be regular or negative, regular RefSpecs indicate
+ * what to include in transport operations while negative RefSpecs indicate
+ * what to exclude in fetch.
+ * <p>
+ * Negative {@link RefSpec}s can't be force, must have only source or
+ * destination. Wildcard patterns are also supported in negative RefSpecs
+ * but they can not go with {@code WildcardMode.REQUIRE_MATCH} because they
+ * are natually one to many mappings.
+ *
+ * <p>
* Specifications are typically one of the following forms:
* <ul>
* <li><code>refs/heads/master</code></li>
@@ -121,6 +135,12 @@ public class RefSpec implements Serializable {
* <li><code>refs/heads/*:refs/heads/master</code></li>
* </ul>
*
+ * Negative specifications are usually like:
+ * <ul>
+ * <li><code>^:refs/heads/master</code></li>
+ * <li><code>^refs/heads/*</code></li>
+ * </ul>
+ *
* @param spec
* string describing the specification.
* @param mode
@@ -133,11 +153,22 @@ public class RefSpec implements Serializable {
public RefSpec(String spec, WildcardMode mode) {
this.allowMismatchedWildcards = mode;
String s = spec;
+
+ if (s.startsWith("^+") || s.startsWith("+^")) {
+ throw new IllegalArgumentException(
+ JGitText.get().invalidNegativeAndForce);
+ }
+
if (s.startsWith("+")) { //$NON-NLS-1$
force = true;
s = s.substring(1);
}
+ if(s.startsWith("^")) {
+ negative = true;
+ s = s.substring(1);
+ }
+
boolean matchPushSpec = false;
final int c = s.lastIndexOf(':');
if (c == 0) {
@@ -181,6 +212,21 @@ public class RefSpec implements Serializable {
}
srcName = checkValid(s);
}
+
+ // Negative refspecs must only have dstName or srcName.
+ if (isNegative()) {
+ if (isNullOrEmpty(srcName) && isNullOrEmpty(dstName)) {
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidRefSpec, spec));
+ }
+ if (!isNullOrEmpty(srcName) && !isNullOrEmpty(dstName)) {
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidRefSpec, spec));
+ }
+ if(wildcard && mode == WildcardMode.REQUIRE_MATCH) {
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().invalidRefSpec, spec));}
+ }
matching = matchPushSpec;
}
@@ -205,13 +251,15 @@ public class RefSpec implements Serializable {
* the specification is invalid.
*/
public RefSpec(String spec) {
- this(spec, WildcardMode.REQUIRE_MATCH);
+ this(spec, spec.startsWith("^") ? WildcardMode.ALLOW_MISMATCH
+ : WildcardMode.REQUIRE_MATCH);
}
private RefSpec(RefSpec p) {
matching = false;
force = p.isForceUpdate();
wildcard = p.isWildcard();
+ negative = p.isNegative();
srcName = p.getSource();
dstName = p.getDestination();
allowMismatchedWildcards = p.allowMismatchedWildcards;
@@ -246,6 +294,10 @@ public class RefSpec implements Serializable {
*/
public RefSpec setForceUpdate(boolean forceUpdate) {
final RefSpec r = new RefSpec(this);
+ if (forceUpdate && isNegative()) {
+ throw new IllegalArgumentException(
+ JGitText.get().invalidNegativeAndForce);
+ }
r.matching = matching;
r.force = forceUpdate;
return r;
@@ -265,6 +317,16 @@ public class RefSpec implements Serializable {
}
/**
+ * Check if this specification is a negative one.
+ *
+ * @return true if this specification is negative.
+ * @since 6.2
+ */
+ public boolean isNegative() {
+ return negative;
+ }
+
+ /**
* Get the source ref description.
* <p>
* During a fetch this is the name of the ref on the remote repository we
@@ -435,6 +497,10 @@ public class RefSpec implements Serializable {
return this;
}
+ private static boolean isNullOrEmpty(String refName) {
+ return refName == null || refName.isEmpty();
+ }
+
/**
* Expand this specification to exactly match a ref.
* <p>
@@ -570,6 +636,9 @@ public class RefSpec implements Serializable {
if (isForceUpdate() != b.isForceUpdate()) {
return false;
}
+ if(isNegative() != b.isNegative()) {
+ return false;
+ }
if (isMatching()) {
return b.isMatching();
} else if (b.isMatching()) {
@@ -587,6 +656,9 @@ public class RefSpec implements Serializable {
if (isForceUpdate()) {
r.append('+');
}
+ if(isNegative()) {
+ r.append('^');
+ }
if (isMatching()) {
r.append(':');
} else {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
index 2f3160bb8e..c4e105ec4a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java
@@ -16,10 +16,7 @@ import java.io.Serializable;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
import org.eclipse.jgit.lib.Config;
@@ -54,10 +51,6 @@ public class RemoteConfig implements Serializable {
private static final String KEY_TIMEOUT = "timeout"; //$NON-NLS-1$
- private static final String KEY_INSTEADOF = "insteadof"; //$NON-NLS-1$
-
- private static final String KEY_PUSHINSTEADOF = "pushinsteadof"; //$NON-NLS-1$
-
private static final boolean DEFAULT_MIRROR = false;
/** Default value for {@link #getUploadPack()} if not specified. */
@@ -135,10 +128,10 @@ public class RemoteConfig implements Serializable {
String val;
vlst = rc.getStringList(SECTION, name, KEY_URL);
- Map<String, String> insteadOf = getReplacements(rc, KEY_INSTEADOF);
+ UrlConfig urls = new UrlConfig(rc);
uris = new ArrayList<>(vlst.length);
for (String s : vlst) {
- uris.add(new URIish(replaceUri(s, insteadOf)));
+ uris.add(new URIish(urls.replace(s)));
}
String[] plst = rc.getStringList(SECTION, name, KEY_PUSHURL);
pushURIs = new ArrayList<>(plst.length);
@@ -148,11 +141,9 @@ public class RemoteConfig implements Serializable {
if (pushURIs.isEmpty()) {
// Would default to the uris. If we have pushinsteadof, we must
// supply rewritten push uris.
- Map<String, String> pushInsteadOf = getReplacements(rc,
- KEY_PUSHINSTEADOF);
- if (!pushInsteadOf.isEmpty()) {
+ if (urls.hasPushReplacements()) {
for (String s : vlst) {
- String replaced = replaceUri(s, pushInsteadOf);
+ String replaced = urls.replacePush(s);
if (!s.equals(replaced)) {
pushURIs.add(new URIish(replaced));
}
@@ -248,39 +239,6 @@ public class RemoteConfig implements Serializable {
rc.unset(SECTION, getName(), key);
}
- private Map<String, String> getReplacements(final Config config,
- final String keyName) {
- final Map<String, String> replacements = new HashMap<>();
- for (String url : config.getSubsections(KEY_URL))
- for (String insteadOf : config.getStringList(KEY_URL, url, keyName))
- replacements.put(insteadOf, url);
- return replacements;
- }
-
- private String replaceUri(final String uri,
- final Map<String, String> replacements) {
- if (replacements.isEmpty()) {
- return uri;
- }
- Entry<String, String> match = null;
- for (Entry<String, String> replacement : replacements.entrySet()) {
- // Ignore current entry if not longer than previous match
- if (match != null
- && match.getKey().length() > replacement.getKey()
- .length()) {
- continue;
- }
- if (!uri.startsWith(replacement.getKey())) {
- continue;
- }
- match = replacement;
- }
- if (match != null) {
- return match.getValue() + uri.substring(match.getKey().length());
- }
- return uri;
- }
-
/**
* Get the local name this remote configuration is recognized as.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
index 8a8d977ed3..96c7be5b97 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * 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
@@ -28,6 +28,8 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Unmultiplexes the data portion of a side-band channel.
@@ -46,6 +48,10 @@ import org.eclipse.jgit.util.RawParseUtils;
* @since 4.11
*/
public class SideBandInputStream extends InputStream {
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(SideBandInputStream.class);
+
static final int CH_DATA = 1;
static final int CH_PROGRESS = 2;
static final int CH_ERROR = 3;
@@ -210,6 +216,21 @@ public class SideBandInputStream extends InputStream {
monitor.beginTask(remote(currentTask), totalWorkUnits);
}
+ /**
+ * Forces any buffered progress messages to be written.
+ */
+ void drainMessages() {
+ if (!progressBuffer.isEmpty()) {
+ try {
+ progress("\n"); //$NON-NLS-1$
+ } catch (IOException e) {
+ // Just log; otherwise this IOException might hide a real
+ // TransportException
+ LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+
private static String remote(String msg) {
String prefix = JGitText.get().prefixRemote;
StringBuilder r = new StringBuilder(prefix.length() + msg.length() + 1);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
index 1e98a56f79..a0194ea8b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
@@ -1,6 +1,6 @@
/*
* 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
@@ -36,15 +36,35 @@ import org.eclipse.jgit.util.SystemReader;
*/
public abstract class SshSessionFactory {
- private static volatile SshSessionFactory INSTANCE = loadSshSessionFactory();
+ private static class DefaultFactory {
- private static SshSessionFactory loadSshSessionFactory() {
- ServiceLoader<SshSessionFactory> loader = ServiceLoader.load(SshSessionFactory.class);
- Iterator<SshSessionFactory> iter = loader.iterator();
- if(iter.hasNext()) {
- return iter.next();
+ private static volatile SshSessionFactory INSTANCE = loadSshSessionFactory();
+
+ private static SshSessionFactory loadSshSessionFactory() {
+ ServiceLoader<SshSessionFactory> loader = ServiceLoader
+ .load(SshSessionFactory.class);
+ Iterator<SshSessionFactory> iter = loader.iterator();
+ if (iter.hasNext()) {
+ return iter.next();
+ }
+ return null;
+ }
+
+ private DefaultFactory() {
+ // No instantiation
+ }
+
+ public static SshSessionFactory getInstance() {
+ return INSTANCE;
+ }
+
+ public static void setInstance(SshSessionFactory newFactory) {
+ if (newFactory != null) {
+ INSTANCE = newFactory;
+ } else {
+ INSTANCE = loadSshSessionFactory();
+ }
}
- return null;
}
/**
@@ -57,7 +77,7 @@ public abstract class SshSessionFactory {
* @return factory the current factory for this JVM.
*/
public static SshSessionFactory getInstance() {
- return INSTANCE;
+ return DefaultFactory.getInstance();
}
/**
@@ -68,11 +88,7 @@ public abstract class SshSessionFactory {
* {@code null} the default factory will be restored.
*/
public static void setInstance(SshSessionFactory newFactory) {
- if (newFactory != null) {
- INSTANCE = newFactory;
- } else {
- INSTANCE = loadSshSessionFactory();
- }
+ DefaultFactory.setInstance(newFactory);
}
/**
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 0eab4434ed..3222d6330c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -1230,7 +1230,9 @@ public abstract class Transport implements AutoCloseable {
* @param toFetch
* specification of refs to fetch locally. May be null or the
* empty collection to use the specifications from the
- * RemoteConfig. Source for each RefSpec can't be null.
+ * RemoteConfig. May contains regular and negative
+ * {@link RefSpec}s. Source for each regular RefSpec can't
+ * be null.
* @return information describing the tracking refs updated.
* @throws org.eclipse.jgit.errors.NotSupportedException
* this transport implementation does not support fetching
@@ -1264,7 +1266,9 @@ public abstract class Transport implements AutoCloseable {
* @param toFetch
* specification of refs to fetch locally. May be null or the
* empty collection to use the specifications from the
- * RemoteConfig. Source for each RefSpec can't be null.
+ * RemoteConfig. May contains regular and negative
+ * {@link RefSpec}s. Source for each regular RefSpec can't
+ * be null.
* @param branch
* the initial branch to check out when cloning the repository.
* Can be specified as ref name (<code>refs/heads/master</code>),
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UrlConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UrlConfig.java
new file mode 100644
index 0000000000..574fcf806d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UrlConfig.java
@@ -0,0 +1,120 @@
+/*
+ * 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.transport;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * Support for URL translations via git configs {@code url.<base>.insteadOf} and
+ * {@code url.<base>.pushInsteadOf}.
+ *
+ * @since 6.2
+ */
+public class UrlConfig {
+
+ private static final String KEY_INSTEADOF = "insteadof"; //$NON-NLS-1$
+
+ private static final String KEY_PUSHINSTEADOF = "pushinsteadof"; //$NON-NLS-1$
+
+ private static final String SECTION_URL = "url"; //$NON-NLS-1$
+
+ private final Config config;
+
+ private Map<String, String> insteadOf;
+
+ private Map<String, String> pushInsteadOf;
+
+ /**
+ * Creates a new {@link UrlConfig} instance.
+ *
+ * @param config
+ * {@link Config} to read values from
+ */
+ public UrlConfig(Config config) {
+ this.config = config;
+ }
+
+ /**
+ * Performs replacements as defined by git config
+ * {@code url.<base>.insteadOf}. If there is no match, the input is returned
+ * unchanged.
+ *
+ * @param url
+ * to substitute
+ * @return the {@code url} with substitution applied
+ */
+ public String replace(String url) {
+ if (insteadOf == null) {
+ insteadOf = load(KEY_INSTEADOF);
+ }
+ return replace(url, insteadOf);
+ }
+
+ /**
+ * Tells whether there are push replacements.
+ *
+ * @return {@code true} if there are push replacements, {@code false}
+ * otherwise
+ */
+ public boolean hasPushReplacements() {
+ if (pushInsteadOf == null) {
+ pushInsteadOf = load(KEY_PUSHINSTEADOF);
+ }
+ return !pushInsteadOf.isEmpty();
+ }
+
+ /**
+ * Performs replacements as defined by git config
+ * {@code url.<base>.pushInsteadOf}. If there is no match, the input is
+ * returned unchanged.
+ *
+ * @param url
+ * to substitute
+ * @return the {@code url} with substitution applied
+ */
+ public String replacePush(String url) {
+ if (pushInsteadOf == null) {
+ pushInsteadOf = load(KEY_PUSHINSTEADOF);
+ }
+ return replace(url, pushInsteadOf);
+ }
+
+ private Map<String, String> load(String key) {
+ Map<String, String> replacements = new HashMap<>();
+ for (String url : config.getSubsections(SECTION_URL)) {
+ for (String prefix : config.getStringList(SECTION_URL, url, key)) {
+ replacements.put(prefix, url);
+ }
+ }
+ return replacements;
+ }
+
+ private String replace(String uri, Map<String, String> replacements) {
+ Entry<String, String> match = null;
+ for (Entry<String, String> replacement : replacements.entrySet()) {
+ // Ignore current entry if not longer than previous match
+ if (match != null && match.getKey().length() > replacement.getKey()
+ .length()) {
+ continue;
+ }
+ if (uri.startsWith(replacement.getKey())) {
+ match = replacement;
+ }
+ }
+ if (match != null) {
+ return match.getValue() + uri.substring(match.getKey().length());
+ }
+ return uri;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java
new file mode 100644
index 0000000000..da1684630b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Equality.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022, Fabio Ponciroli <ponch78@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.util;
+
+/**
+ * Equality utilities.
+ *
+ * @since: 6.2
+ */
+public class Equality {
+
+ /**
+ * Compare by reference
+ *
+ * @param a
+ * First object to compare
+ * @param b
+ * Second object to compare
+ * @return {@code true} if the objects are identical, {@code false}
+ * otherwise
+ *
+ * @since 6.2
+ */
+ @SuppressWarnings("ReferenceEquality")
+ public static <T> boolean isSameInstance(T a, T b) {
+ return a == b;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index b9dd9baa61..f013e7e095 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -17,6 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.nio.channels.FileChannel;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.CopyOption;
@@ -655,6 +656,99 @@ public class FileUtils {
}
/**
+ * Like a {@link java.util.function.Function} but throwing an
+ * {@link Exception}.
+ *
+ * @param <A>
+ * input type
+ * @param <B>
+ * output type
+ * @since 6.2
+ */
+ @FunctionalInterface
+ public interface IOFunction<A, B> {
+
+ /**
+ * Performs the function.
+ *
+ * @param t
+ * input to operate on
+ * @return the output
+ * @throws Exception
+ * if a problem occurs
+ */
+ B apply(A t) throws Exception;
+ }
+
+ private static void backOff(long delay, IOException cause)
+ throws IOException {
+ try {
+ Thread.sleep(delay);
+ } catch (InterruptedException e) {
+ IOException interruption = new InterruptedIOException();
+ interruption.initCause(e);
+ interruption.addSuppressed(cause);
+ Thread.currentThread().interrupt(); // Re-set flag
+ throw interruption;
+ }
+ }
+
+ /**
+ * Invokes the given {@link IOFunction}, performing a limited number of
+ * re-tries if exceptions occur that indicate either a stale NFS file handle
+ * or that indicate that the file may be written concurrently.
+ *
+ * @param <T>
+ * result type
+ * @param file
+ * to read
+ * @param reader
+ * for reading the file and creating an instance of {@code T}
+ * @return the result of the {@code reader}, or {@code null} if the file
+ * does not exist
+ * @throws Exception
+ * if a problem occurs
+ * @since 6.2
+ */
+ public static <T> T readWithRetries(File file,
+ IOFunction<File, ? extends T> reader)
+ throws Exception {
+ int maxStaleRetries = 5;
+ int retries = 0;
+ long backoff = 50;
+ while (true) {
+ try {
+ try {
+ return reader.apply(file);
+ } catch (IOException e) {
+ if (FileUtils.isStaleFileHandleInCausalChain(e)
+ && retries < maxStaleRetries) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(MessageFormat.format(
+ JGitText.get().packedRefsHandleIsStale,
+ Integer.valueOf(retries)), e);
+ }
+ retries++;
+ continue;
+ }
+ throw e;
+ }
+ } catch (FileNotFoundException noFile) {
+ if (!file.isFile()) {
+ return null;
+ }
+ // Probably Windows and some other thread is writing the file
+ // concurrently.
+ if (backoff > 1000) {
+ throw noFile;
+ }
+ backOff(backoff, noFile);
+ backoff *= 2; // 50, 100, 200, 400, 800 ms
+ }
+ }
+ }
+
+ /**
* @param file
* @return {@code true} if the passed file is a symbolic link
*/
diff --git a/pom.xml b/pom.xml
index 81093c0a44..53afbbe40f 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.1.1-SNAPSHOT</version>
+ <version>6.2.0-SNAPSHOT</version>
<name>JGit - Parent</name>
<url>${jgit-url}</url>
@@ -150,11 +150,11 @@
<java.version>11</java.version>
<bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
- <jgit-last-release-version>6.0.0.202111291000-r</jgit-last-release-version>
+ <jgit-last-release-version>6.1.0.202203080745-r</jgit-last-release-version>
<ant-version>1.10.12</ant-version>
<apache-sshd-version>2.8.0</apache-sshd-version>
<jsch-version>0.1.55</jsch-version>
- <jzlib-version>1.1.1</jzlib-version>
+ <jzlib-version>1.1.3</jzlib-version>
<javaewah-version>1.1.13</javaewah-version>
<junit-version>4.13.2</junit-version>
<test-fork-count>1C</test-fork-count>
@@ -168,7 +168,7 @@
<httpcore-version>4.4.14</httpcore-version>
<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>
+ <tycho-extras-version>2.6.0</tycho-extras-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>