Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Sohn2020-11-28 20:02:09 +0000
committerMatthias Sohn2020-11-28 20:51:50 +0000
commit286ad23cb56ffeac77d4bfd03be575358fd5217c (patch)
treedc075c6b1d1e813f253ec465813b6251d9d07d61
parent4887894ffd637030a311ca8d60b78515b1a5cf35 (diff)
parent4f2065d145c3fa3f8ad3de28af3ee5dfeb74c765 (diff)
downloadjgit-286ad23cb56ffeac77d4bfd03be575358fd5217c.tar.gz
jgit-286ad23cb56ffeac77d4bfd03be575358fd5217c.tar.xz
jgit-286ad23cb56ffeac77d4bfd03be575358fd5217c.zip
Merge branch 'master' into next
* master: Remove unused imports Silence API warnings Remove erraneously merged source features Add support for reading symrefs from pack capabilities Prepare 5.3.9-SNAPSHOT builds JGit v5.3.8.202011260953-r Prepare 5.1.15-SNAPSHOT builds JGit v5.1.14.202011251942-r GC#deleteOrphans: log warning for deleted orphaned files GC#deleteOrphans: handle failure to list files in pack directory Ensure that GC#deleteOrphans respects pack lock Prepare 5.10.0-SNAPSHOT builds JGit v5.10.0.202011251205-m3 PacketLineIn: ensure that END != DELIM Update Orbit to S20201118210000 and add target for 4.18 PacketLineIn: ensure that END != DELIM PacketLineIn: ensure that END != DELIM Allow to resolve a conflict by checking out a file Update Orbit to I20201111205634 Document that setLastModified sets time of symlink target Fix bug in PerformanceLogContext Fix IOException occurring during gc Prepare 5.10.0-SNAPSHOT builds JGit v5.10.0.202011041322-m2 Revert "Client-side protocol V2 support for fetching" Close Repository to fix tests failing on Windows Client-side protocol V2 support for fetching Update slf4j to 1.7.30 Update Orbit to S20201027182932 (2020-12 M2) Fix formatting of config option values Document options in core section supported by JGit Ensure .gitmodules is loaded when accessing submodule name Export new package org.eclipse.jgit.logging and import it where used Ensure GC.deleteOrphans() can delete read-only orphaned files on Windows Add new performance logging Implement git describe --all Compute time differences with Duration Override config http.userAgent from environment GIT_HTTP_USER_AGENT Upgrade spotbugs-maven-plugin to 4.1.3 Fix OperatorPrecedence warning flagged by error prone UploadPackTest#testUploadRedundantBytes: ensure test repo is closed ObjectDirectory#selectObjectRepresentation: fix formatting Upgrade ecj to 3.23.0 Support "http.userAgent" and "http.extraHeader" from the git config sshd: better error report when user cancels authentication API filters for PackStatistics.Accumulator Add TypedConfigGetter.getPath() Make Javadoc consistent for PackStatistics fields Measure time taken for reachability checks Measure time taken for negotiation in protocol V2 IndexDiffFilter: handle path prefixes correctly sshd: support the ProxyJump ssh config Upgrade jacoco-maven-plugin to 0.8.6 ReceivePackStats: Add size and count of unnecessary pushed objects Upgrade maven-project-info-reports-plugin to 3.1.1 Prepare 5.9.1-SNAPSHOT builds JGit v5.9.0.202009080501-r [releng] Enable japicmp for the fragments added in 5.8.0 GitlinkMergeTest: fix boxing warnings Remove unused API problem filters Add missing since tag on BundleWriter#addObjectsAsIs SshdSession: close channel gracefully GPG: include signer's user ID in the signature jgit: Add DfsBundleWriter Bump Bazel version to 3.5.0 Upgrade maven-resources-plugin to 3.2.0 Upgrade plexus-compiler version to 2.8.8 [bazel] Add missing dependency to slf4j-api [errorprone] DirCacheEntry: make clear operator precedence [errorprone] PackWriter#parallelDeltaSearch: avoid suppressed exception [errorprone] Declare DirCache#version final Add jgit-4.17-staging target platform for 2020-09 Update target platform to R20200831200620 Prepare 5.10.0-SNAPSHOT builds Prepare 5.9.0-SNAPSHOT builds ResolveMerger: do not content-merge gitlinks on del/mod conflicts ResolveMerger: Adding test cases for GITLINK deletion ResolveMerger: choose OURS on gitlink when ignoreConflicts ResolveMerger: improving content merge readability ResolveMerger: extracting createGitLinksMergeResult method ResolveMerger: Adding test cases for GITLINK merge JGit v5.9.0.202008260805-m3 Fix possible NegativeArraySizeException in PackIndexV1 FS: use binary search to determine filesystem timestamp resolution Do not prematurely create directory of jgit's XDG config file FS: write to JGit config in a background thread FS: don't cache fallback if running in background Keep line endings for text files committed with CR/LF on text=auto Delay WindowCache statistics JMX MBean registration [releng] Update plexus-compiler to 2.8.7 DirCache: support index V4 Update javadoc for RemoteSession and SshSessionFactory Fix JSchProcess.waitFor() with time-out sshd: work around a race condition in Apache MINA sshd 2.4.0/2.5.x sshd: store per-session data on the sshd session object FilterSpec: Use BigInteger.ZERO instead of valueOf(0) Do not send empty blob in response to blob:none filter Add support for tree filters when fetching sshd: use PropertyResolver in test FS_POSIX: avoid prompt to install the XCode tools on OS X Remove dependency on JSch from SSH test framework Use LinkedBlockingQueue for executor determining filesystem attributes Update API warning filters Remove unused imports Bazel: Add workspace status command to stamp final artifact DiffFormatter: correctly deal with tracked files in ignored folders Prepare 5.8.2-SNAPSHOT builds JGit v5.8.1.202007141445-r Update Jetty to 9.4.30.v20200611 Fix writing GPG signatures with trailing newline Rename a test method Add a test for upstream bug SSHD-1028 Improve error message when receive.maxCommandBytes is exceeded LfsConnectionFactory#getLfsUrl: Fix unconditional break in for-loop DiffFormatterTest: Add a test to confirm the default rename detection settings Upgrade maven-site-plugin to 3.9.1 Upgrade build-helper-maven-plugin to 3.2.0 Upgrade spotbugs to 4.0.4 MergedReftable: Include the last reftable in determining minUpdateIndex Add new osgi fragments to maven-central deploy scripts PackBitmapIndex: Not buffer inflated bitmap during bitmap creation. Do not require org.assertj.core.annotations Upgrade ecj to 3.22.0 Remove workaround for signing jars using Tycho plugins Use https for URL of jgit website Fix CI information in pom.xml Use gitiles as scm url in pom.xml for browsing source code Update API baseline to 5.8.0.202006091008-r Remove trailing whitespace Change-Id: Ie6bc6954741a47cfbd32c0886bdbd7b594f08b31 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rw-r--r--.bazelrc1
-rw-r--r--.bazelversion2
-rw-r--r--Documentation/config-options.md44
-rw-r--r--WORKSPACE38
-rw-r--r--org.eclipse.jgit.benchmarks/pom.xml2
-rw-r--r--org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.jgit.gpg.bc/pom.xml4
-rw-r--r--org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java39
-rw-r--r--org.eclipse.jgit.junit.ssh/BUILD2
-rw-r--r--org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.jgit.junit.ssh/pom.xml10
-rw-r--r--org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java49
-rw-r--r--org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java146
-rw-r--r--org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java89
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java24
-rw-r--r--org.eclipse.jgit.lfs.test/BUILD1
-rw-r--r--org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16-staging.tpd8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target94
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target94
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.target (renamed from org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16-staging.target)60
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.tpd8
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20200831200620-2020-09.tpd (renamed from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20200519202422.tpd)24
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20201118210000.tpd66
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd34
-rw-r--r--org.eclipse.jgit.packaging/pom.xml2
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java20
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties2
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java4
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java15
-rw-r--r--org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java444
-rw-r--r--org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties10
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationCanceledException.java30
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java257
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPasswordAuthentication.java4
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java113
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java69
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java41
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java8
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java51
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java72
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java245
-rw-r--r--org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java31
-rw-r--r--org.eclipse.jgit.ssh.jsch/pom.xml4
-rw-r--r--org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/JschSession.java2
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.jgit.test/build.properties2
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v4bin0 -> 483 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idxbin0 -> 1033 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idxV2bin0 -> 1041 bytes
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java61
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java47
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java120
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java26
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java13
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java21
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java69
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheAfterCloneTest.java134
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java32
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java142
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java28
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriterTest.java85
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java23
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java20
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java22
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV1Test.java5
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV2Test.java5
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java32
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java90
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java117
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/logging/PerformanceLogContextTest.java95
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/GitlinkMergeTest.java368
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java44
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java1
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BasePackConnectionTest.java233
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java98
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java8
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java18
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java48
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java231
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java43
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFOutputStreamTest.java84
-rw-r--r--org.eclipse.jgit/.settings/.api_filters39
-rw-r--r--org.eclipse.jgit/BUILD23
-rw-r--r--org.eclipse.jgit/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties15
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java43
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java17
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java135
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java32
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java194
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriter.java52
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java17
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java22
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java33
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java36
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java31
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java64
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogContext.java67
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogRecord.java55
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java124
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java39
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java105
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java49
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FilterSpec.java108
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java89
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java21
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java50
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java26
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java30
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java53
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java44
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java45
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java28
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java198
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java38
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java63
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java59
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java22
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java125
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java63
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java35
-rw-r--r--pom.xml47
-rwxr-xr-xtools/maven-central/deploy.rb2
-rwxr-xr-xtools/maven-central/download.rb2
-rw-r--r--tools/workspace_status.py45
169 files changed, 6433 insertions, 1355 deletions
diff --git a/.bazelrc b/.bazelrc
index 3a61f8cb7a..e24be88639 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,3 +1,4 @@
+build --workspace_status_command="python ./tools/workspace_status.py"
build --repository_cache=~/.gerritcodereview/bazel-cache/repository
build --experimental_strict_action_env
build --action_env=PATH
diff --git a/.bazelversion b/.bazelversion
index fd2a01863f..1545d96657 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-3.1.0
+3.5.0
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index 94ef5b9556..d463551762 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -11,15 +11,47 @@
| option | default | git option | description |
|---------|---------|------------|-------------|
-| `core.bigFileThreshold` | `52428800` (50 MiB) | &#x2705; | Maximum file size that will be delta compressed. Files larger than this size are stored deflated, without attempting delta compression. |
-| `core.compression` | `-1` (default compression) | &#x2705; | An integer -1..9, indicating a default compression level. -1 is the zlib default. 0 means no compression, and 1..9 are various speed/size tradeoffs, 9 being slowest.|
+| `core.attributesFile` | | &#x2705; | In addition to `.gitattributes` (per-directory) and `.git/info/attributes`, Git looks into this file for attributes . Path expansions are made the same way as for `core.excludesFile`. |
+| `core.autocrlf` | `false` | &#x2705; | Setting this variable to `true` is the same as setting the text attribute to `auto` on all files and `core.eol` to `crlf`. Set to `true` if you want to have CRLF line endings in your working directory and the repository has LF line endings. This variable can be set to `input`, in which case no output conversion is performed. |
+| `core.bare` | set automatically on init or clone | &#x2705; | If true this repository is assumed to be bare and has no working directory associated with it. If this is the case a number of commands that require a working directory will be disabled |
+| `core.bigFileThreshold` | `50 MiB` | &#x2705; | Files larger than this size are stored deflated, without attempting delta compression. Storing large files without delta compression avoids excessive memory usage, at the slight expense of increased disk usage. Additionally files larger than this size are always treated as binary. |
+| `core.checkstat` | | &#x2705; | When missing or is set to `default`, many fields in the stat structure are checked to detect if a file has been modified since Git looked at it. Checks as much of the dircache stat info as possible (in JGit limited by Java filesystem API). When set to `minimum` only checks the size and whole second part of time stamp when comparing the stat info in the dircache with actual file stat info. |
+| `core.compression` | `-1` (zlib default) | &#x2705; | An integer `-1..9`, indicating a default compression level. `-1` is the zlib default. `0` means no compression, and `1..9` are various speed/size tradeoffs, `9` being slowest.|
+| `core.deltaBaseCacheLimit` | `10 MiB` | &#x2705; | Maximum number of bytes to reserve for caching base objects that multiple deltafied objects reference. By storing the entire decompressed base object in a cache Git is able to avoid unpacking and decompressing frequently used base objects multiple times. |
+| `core.dfs.blockLimit` | `30 MiB` | &#x20DE; | Maximum number bytes of heap memory to dedicate to caching pack file data in DFS block cache. |
+| `core.dfs.blockSize` | `64 kiB` | &#x20DE; | Size in bytes of a single window read in from the pack file into the DFS block cache. |
+| `core.dfs.concurrencyLevel` | `32` | &#x20DE; | The estimated number of threads concurrently accessing the DFS block cache. |
+| `core.dfs.deltaBaseCacheLimit` | `10 MiB` | &#x20DE; | Maximum number of bytes to hold in per-reader DFS delta base cache. |
+| `core.dfs.streamFileThreshold` | `50 MiB` | &#x20DE; | The size threshold beyond which objects must be streamed. |
+| `core.dfs.streamBuffer` | Block size of the pack | &#x20DE; | Number of bytes to use for buffering when streaming a pack file during copying. If 0 the block size of the pack is used|
+| `core.dfs.streamRatio` | `0.30` | &#x20DE; | Ratio of DFS block cache to occupy with a copied pack. Values between `0` and `1.0`. |
+| `core.dirNoGitLinks` | `false` | &#x20DE; | If set to `true` avoid checking for submodules. See [bug 436200](https://bugs.eclipse.org/bugs/show_bug.cgi?id=436200). |
+| `core.eol` | `native` | &#x2705; | Sets the line ending type to use in the working directory for files that are marked as text (either by having the text attribute set, or by having `text=auto` and Git auto-detecting the contents as text). Alternatives are `lf`, `crlf` and `native`, which uses the platform’s native line ending. |
+| `core.excludesFile` | | &#x2705; | Specifies the pathname to the file that contains patterns to describe paths that are not meant to be tracked, in addition to `.gitignore` (per-directory) and `.git/info/exclude`. |
+| `core.fileMode` | Auto detects if file modes are supported | &#x2705; | Tells Git if the executable bit of files in the working tree is to be honored. |
+| `core.hideDotFiles` | `dotGitOnly` | &#x2705; | Windows only. If `true`, mark newly-created directories and files whose name starts with a dot as hidden. If `dotGitOnly`, only the `.git/` directory is hidden, but no other files starting with a dot. |
+| `core.hooksPath` | `$GIT_DIR/hooks` | &#x2705; | Path to look for hooks. |
+| `core.logAllRefUpdates` | `true` in a repository with working tree, `false` in bare repository | &#x2705; | Enable the reflog. |
+| `core.packedGitLimit` | `10 MiB` | &#x2705; | Maximum number of bytes to cache in memory from pack files. |
+| `core.packedGitMmap` | `false` | &#x2705; | Whether to use Java NIO virtual memory mapping for JGit buffer cache. When set to `true` enables use of Java NIO virtual memory mapping for cache windows, `false` reads entire window into a `byte[]` with standard read calls. `true` is experimental and may cause instabilities and crashes since Java doesn't support explicit unmapping of file regions mapped to virtual memory. |
+| `core.packedGitOpenFiles` | `128` | &#x20DE; | Maximum number of streams to open at a time. Open packs count against the process limits. |
+| `core.packedGitUseStrongRefs` | `false` | &#x20DE; | Whether the window cache should use strong references (`true`) or SoftReferences (`false`). When `false` the JVM will drop data cached in the JGit block cache when heap usage comes close to the maximum heap size. |
+| `core.packedGitWindowSize` | `8 kiB` | &#x2705; | Number of bytes of a pack file to load into memory in a single read operation. This is the "page size" of the JGit buffer cache, used for all pack access operations. All disk IO occurs as single window reads. Setting this too large may cause the process to load more data than is required; setting this too small may increase the frequency of read() system calls. |
+| `core.precomposeUnicode` | `true` on Mac OS | &#x2705; | MacOS only. When `true`, JGit reverts the unicode decomposition of filenames done by Mac OS. |
+| `core.quotePath` | `true` | &#x2705; | Commands that output paths (e.g. ls-files, diff), will quote "unusual" characters in the pathname by enclosing the pathname in double-quotes and escaping those characters with backslashes in the same way C escapes control characters (e.g. `\t` for TAB, `\n` for LF, `\\` for backslash) or bytes with values larger than `0x80` (e.g. octal `\302\265` for "micro" in UTF-8). |
+| `core.repositoryFormatVersion` | `1` | &#x20DE; | Internal version identifying the repository format and layout version. Don't set manually. |
+| `core.streamFileThreshold` | `50 MiB` | &#x20DE; | The size threshold beyond which objects must be streamed. |
+| `core.supportsAtomicFileCreation` | `true` | &#x20DE; | Whether the filesystem supports atomic file creation. |
+| `core.symlinks` | Auto detect if filesystem supports symlinks| &#x2705; | If false, symbolic links are checked out as small plain files that contain the link text. |
+| `core.trustFolderStat` | `true` | &#x20DE; | Whether to trust the pack folder's modification time. If `false` JGit will always scan the `.git/objects/pack` folder to check for new pack files. This can help to workaround caching issues on NFS, but reduces performance. If set to `true` it uses the `lastmodified` attribute of the folder and assumes that no new pack files can be in this folder if its modification time has not changed. |
+| `core.worktree` | Root directory of the working tree if it is not the parent directory of the `.git` directory | &#x2705; | The path to the root of the working tree. |
## __gc__ options
| option | default | git option | description |
|---------|---------|------------|-------------|
-| `gc.aggressiveDepth` | 50 | &#x2705; | The depth parameter used in the delta compression algorithm used by aggressive garbage collection. |
-| `gc.aggressiveWindow` | 250 | &#x2705; | The window size parameter used in the delta compression algorithm used by aggressive garbage collection. |
+| `gc.aggressiveDepth` | `50` | &#x2705; | The depth parameter used in the delta compression algorithm used by aggressive garbage collection. |
+| `gc.aggressiveWindow` | `250` | &#x2705; | The window size parameter used in the delta compression algorithm used by aggressive garbage collection. |
| `gc.auto` | `6700` | &#x2705; | Number of loose objects until auto gc combines all loose objects into a pack and consolidates all existing packs into one. Setting to 0 disables automatic packing of loose objects. |
| `gc.autoDetach` | `true` | &#x2705; | Make auto gc return immediately and run in background. |
| `gc.autoPackLimit` | `50` | &#x2705; | Number of packs until auto gc consolidates existing packs (except those marked with a .keep file) into a single pack. Setting `gc.autoPackLimit` to 0 disables automatic consolidation of packs. |
@@ -41,11 +73,11 @@
| `pack.compression` | `core.compression` | &#x2705; | Compression level applied to objects in the pack. |
| `pack.cutDeltaChains` | `false` | &#x20DE; | Whether existing delta chains should be cut at {@link #getMaxDeltaDepth() |
| `pack.deltaCacheLimit` | `100` | &#x2705; | Maximum size in bytes of a delta to cache. |
-| `pack.deltaCacheSize` | `52428800` (50 MiB) | &#x2705; | Size of the in-memory delta cache. |
+| `pack.deltaCacheSize` | `50 MiB` | &#x2705; | Size of the in-memory delta cache. |
| `pack.deltaCompression` | `true` | &#x20DE; | Whether the writer will create new deltas on the fly. `true` if the pack writer will create a new delta when either `pack.reuseDeltas` is false, or no suitable delta is available for reuse. |
| `pack.depth` | `50` | &#x2705; | Maximum depth of delta chain set up for the pack writer. |
| `pack.indexVersion` | `2` | &#x2705; | Pack index file format version. |
-| `pack.minSizePreventRacyPack` | `104857600` (100 MiB) | &#x20DE; | Minimum packfile size for which we wait before opening a newly written pack to prevent its lastModified timestamp could be racy if `pack.waitPreventRacyPack` is `true`. |
+| `pack.minSizePreventRacyPack` | `100 MiB` | &#x20DE; | Minimum packfile size for which we wait before opening a newly written pack to prevent its lastModified timestamp could be racy if `pack.waitPreventRacyPack` is `true`. |
| `pack.preserveOldPacks` | `false` | &#x20DE; | Whether to preserve old packs in a preserved directory. |
| `prunePreserved`, only via API of PackConfig | `false` | &#x20DE; | Whether to remove preserved pack files in a preserved directory. |
| `pack.reuseDeltas` | `true` |&#x20DE; | Whether to reuse deltas existing in repository. |
diff --git a/WORKSPACE b/WORKSPACE
index 509cf6d094..7651cba4ee 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -107,8 +107,8 @@ maven_jar(
maven_jar(
name = "commons-codec",
- artifact = "commons-codec:commons-codec:1.13",
- sha1 = "3f18e1aa31031d89db6f01ba05d501258ce69d2c",
+ artifact = "commons-codec:commons-codec:1.14",
+ sha1 = "3cb1181b2141a7e752f5bdc998b7ef1849f726cf",
)
maven_jar(
@@ -119,14 +119,14 @@ maven_jar(
maven_jar(
name = "log-api",
- artifact = "org.slf4j:slf4j-api:1.7.2",
- sha1 = "0081d61b7f33ebeab314e07de0cc596f8e858d97",
+ artifact = "org.slf4j:slf4j-api:1.7.30",
+ sha1 = "b5a4b6d16ab13e34a88fae84c35cd5d68cac922c",
)
maven_jar(
name = "slf4j-simple",
- artifact = "org.slf4j:slf4j-simple:1.7.2",
- sha1 = "760055906d7353ba4f7ce1b8908bc6b2e91f39fa",
+ artifact = "org.slf4j:slf4j-simple:1.7.30",
+ sha1 = "e606eac955f55ecf1d8edcccba04eb8ac98088dd",
)
maven_jar(
@@ -209,48 +209,48 @@ maven_jar(
sha1 = "3edcfe49d2c6053a70a2a47e4e1c2f94998a49cf",
)
-JETTY_VER = "9.4.28.v20200408"
+JETTY_VER = "9.4.30.v20200611"
maven_jar(
name = "jetty-servlet",
artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER,
- sha1 = "7df27a6d73e3094ad94ea4f32e3e6597cecbdf38",
- src_sha1 = "49da8455dd5760b7c5961df3b1e7d1490ff9723e",
+ sha1 = "ca3dea2cd34ee88cec017001603af0c9e74781d6",
+ src_sha1 = "6908f24428060bd542bddfa3e89e03d0dbbc2a6d",
)
maven_jar(
name = "jetty-security",
artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER,
- sha1 = "d5fe6851f14d1375e4b4ab1818475bfd929cf517",
- src_sha1 = "204f19ac7e4df9f6f68df1910154d7667ecd78e8",
+ sha1 = "1a5261f6ad4081ad9e9bb01416d639931d391273",
+ src_sha1 = "6ca41b34aa4f84c267603edd4b069122bd5f17d3",
)
maven_jar(
name = "jetty-server",
artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER,
- sha1 = "9c2cbd96426be38b1273ec87ae21e2696688a737",
- src_sha1 = "83454098deb880ecc7168252578f712c06a5504b",
+ sha1 = "e5ede3724d062717d0c04e4c77f74fe8115c2a6f",
+ src_sha1 = "c8b02a47a35c1f083b310cbd202738cf08bc1d55",
)
maven_jar(
name = "jetty-http",
artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER,
- sha1 = "dd56750ea7410c925f1fbae973c0a19cce5a0a68",
- src_sha1 = "1ef8d10cb5ce5694f12650cbb49b31008c673182",
+ sha1 = "cd6223382e4f82b9ea807d8cdb04a23e5d629f1c",
+ src_sha1 = "00520c04b10609b981159b5ca284b5a158c077a9",
)
maven_jar(
name = "jetty-io",
artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER,
- sha1 = "adda6786588a922f834e9c33c7db5f1484310f44",
- src_sha1 = "4e7756e00b97b439d404e6a682bb1cdeb36fc887",
+ sha1 = "9c360d08e903b2dbd5d1f8e889a32046948628ce",
+ src_sha1 = "dac8f8a3f84afdd3686d36f58b5ccb276961b8ce",
)
maven_jar(
name = "jetty-util",
artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER,
- sha1 = "118d2a44721885a04238aee21a5055dc1ab3818a",
- src_sha1 = "e2e6d7c90e4126645d2667014d02f0732c08c948",
+ sha1 = "39ec6aa4745952077f5407cb1394d8ba2db88b13",
+ src_sha1 = "f41f9391f91884a79350f3ad9b09b8e46c9be0ec",
)
BOUNCYCASTLE_VER = "1.65"
diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml
index 1d735bd9de..5941f13642 100644
--- a/org.eclipse.jgit.benchmarks/pom.xml
+++ b/org.eclipse.jgit.benchmarks/pom.xml
@@ -179,7 +179,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
- <version>3.0.0</version>
+ <version>3.1.1</version>
</plugin>
</plugins>
</pluginManagement>
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
index aa851a9d5d..b59a850ea3 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -8,8 +8,7 @@ Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-Version: 6.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.assertj.core.annotations;version="3.14.0",
- org.bouncycastle.bcpg;version="[1.65.0,2.0.0)",
+Import-Package: org.bouncycastle.bcpg;version="[1.65.0,2.0.0)",
org.bouncycastle.gpg;version="[1.65.0,2.0.0)",
org.bouncycastle.gpg.keybox;version="[1.65.0,2.0.0)",
org.bouncycastle.gpg.keybox.jcajce;version="[1.65.0,2.0.0)",
diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml
index 64f784d1d3..833d23ceba 100644
--- a/org.eclipse.jgit.gpg.bc/pom.xml
+++ b/org.eclipse.jgit.gpg.bc/pom.xml
@@ -128,7 +128,6 @@
</configuration>
</plugin>
- <!-- No previous version to compare to
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
@@ -170,13 +169,11 @@
</execution>
</executions>
</plugin>
- -->
</plugins>
</build>
<reporting>
<plugins>
- <!-- No previous version to compare to
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
@@ -217,7 +214,6 @@
<skip>false</skip>
</configuration>
</plugin>
- -->
</plugins>
</reporting>
</project>
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
index c6ecdbe6da..ea159c547d 100644
--- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
+++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java
@@ -15,6 +15,7 @@ import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
+import java.util.Iterator;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
@@ -22,6 +23,7 @@ import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
@@ -38,6 +40,7 @@ import org.eclipse.jgit.lib.GpgSignature;
import org.eclipse.jgit.lib.GpgSigner;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.util.StringUtils;
/**
* GPG Signer using BouncyCastle library
@@ -126,17 +129,32 @@ public class BouncyCastleGpgSigner extends GpgSigner {
privateKey = secretKey
.extractPrivateKey(decryptorBuilder.build(passphrase));
}
+ PGPPublicKey publicKey = secretKey.getPublicKey();
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(
- secretKey.getPublicKey().getAlgorithm(),
+ publicKey.getAlgorithm(),
HashAlgorithmTags.SHA256).setProvider(
BouncyCastleProvider.PROVIDER_NAME));
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);
- PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator();
- subpacketGenerator.setIssuerFingerprint(false,
- secretKey.getPublicKey());
+ PGPSignatureSubpacketGenerator subpackets = new PGPSignatureSubpacketGenerator();
+ subpackets.setIssuerFingerprint(false, publicKey);
+ // Also add the signer's user ID. Note that GPG uses only the e-mail
+ // address part.
+ String userId = committer.getEmailAddress();
+ Iterator<String> userIds = publicKey.getUserIDs();
+ if (userIds.hasNext()) {
+ String keyUserId = userIds.next();
+ if (!StringUtils.isEmptyOrNull(keyUserId)
+ && (userId == null || !keyUserId.contains(userId))) {
+ // Not the committer's key?
+ userId = extractSignerId(keyUserId);
+ }
+ }
+ if (userId != null) {
+ subpackets.setSignerUserID(false, userId);
+ }
signatureGenerator
- .setHashedSubpackets(subpacketGenerator.generate());
+ .setHashedSubpackets(subpackets.generate());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (BCPGOutputStream out = new BCPGOutputStream(
new ArmoredOutputStream(buffer))) {
@@ -149,4 +167,15 @@ public class BouncyCastleGpgSigner extends GpgSigner {
throw new JGitInternalException(e.getMessage(), e);
}
}
+
+ private String extractSignerId(String pgpUserId) {
+ int from = pgpUserId.indexOf('<');
+ if (from >= 0) {
+ int to = pgpUserId.indexOf('>', from + 1);
+ if (to > from + 1) {
+ return pgpUserId.substring(from + 1, to);
+ }
+ }
+ return pgpUserId;
+ }
}
diff --git a/org.eclipse.jgit.junit.ssh/BUILD b/org.eclipse.jgit.junit.ssh/BUILD
index 61b5ce78cb..f7856b5273 100644
--- a/org.eclipse.jgit.junit.ssh/BUILD
+++ b/org.eclipse.jgit.junit.ssh/BUILD
@@ -13,8 +13,8 @@ java_library(
"//org.eclipse.jgit.ssh.jsch.test:__pkg__",
],
deps = [
- "//lib:jsch",
"//lib:junit",
+ "//lib:slf4j-api",
"//lib:sshd-osgi",
"//lib:sshd-sftp",
# We want these deps to be provided_deps
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
index 2b06d48047..8858c09cbd 100644
--- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -8,8 +8,7 @@ Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: com.jcraft.jsch;version="0.1.55",
- org.apache.sshd.common;version="[2.4.0,2.5.0)",
+Import-Package: org.apache.sshd.common;version="[2.4.0,2.5.0)",
org.apache.sshd.common.config.keys;version="[2.4.0,2.5.0)",
org.apache.sshd.common.file.virtualfs;version="[2.4.0,2.5.0)",
org.apache.sshd.common.helpers;version="[2.4.0,2.5.0)",
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml
index cd4626037f..a6f466016a 100644
--- a/org.eclipse.jgit.junit.ssh/pom.xml
+++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -58,16 +58,6 @@
</dependency>
<dependency>
- <groupId>com.jcraft</groupId>
- <artifactId>jsch</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.jcraft</groupId>
- <artifactId>jzlib</artifactId>
- </dependency>
-
- <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>provided</scope>
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java
index 2d284cf1d5..3784741195 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -22,9 +23,14 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.api.errors.TransportException;
+import org.eclipse.jgit.errors.CommandFailedException;
import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.SshSupport;
import org.junit.Test;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theory;
@@ -67,10 +73,45 @@ public abstract class SshTestBase extends SshTestHarness {
defaultCloneDir = new File(getTemporaryDirectory(), "cloned");
}
- @Test(expected = TransportException.class)
+ @Test
public void testSshWithoutConfig() throws Exception {
- cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter", defaultCloneDir, null);
+ assertThrows(TransportException.class,
+ () -> cloneWith("ssh://" + TEST_USER + "@localhost:" + testPort
+ + "/doesntmatter", defaultCloneDir, null));
+ }
+
+ @Test
+ public void testSingleCommand() throws Exception {
+ installConfig("IdentityFile " + privateKey1.getAbsolutePath());
+ String command = SshTestGitServer.ECHO_COMMAND + " 1 without timeout";
+ long start = System.nanoTime();
+ String reply = SshSupport.runSshCommand(
+ new URIish("ssh://" + TEST_USER + "@localhost:" + testPort),
+ null, FS.DETECTED, command, 0); // 0 == no timeout
+ long elapsed = System.nanoTime() - start;
+ assertEquals(command, reply);
+ // Now that we have an idea how long this takes on the test
+ // infrastructure, try again with a timeout.
+ command = SshTestGitServer.ECHO_COMMAND + " 1 expecting no timeout";
+ // Still use a generous timeout.
+ int timeout = 10 * ((int) TimeUnit.NANOSECONDS.toSeconds(elapsed) + 1);
+ reply = SshSupport.runSshCommand(
+ new URIish("ssh://" + TEST_USER + "@localhost:" + testPort),
+ null, FS.DETECTED, command, timeout);
+ assertEquals(command, reply);
+ }
+
+ @Test
+ public void testSingleCommandWithTimeoutExpired() throws Exception {
+ installConfig("IdentityFile " + privateKey1.getAbsolutePath());
+ String command = SshTestGitServer.ECHO_COMMAND + " 2 EXPECTING TIMEOUT";
+
+ CommandFailedException e = assertThrows(CommandFailedException.class,
+ () -> SshSupport.runSshCommand(new URIish(
+ "ssh://" + TEST_USER + "@localhost:" + testPort), null,
+ FS.DETECTED, command, 1));
+ assertTrue(e.getMessage().contains(command));
+ assertTrue(e.getMessage().contains("time"));
}
@Test
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
index 03e2855829..ab8e0c1ca0 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestGitServer.java
@@ -12,6 +12,8 @@ package org.eclipse.jgit.junit.ssh;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
@@ -22,8 +24,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.PropertyResolver;
import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
@@ -66,6 +70,16 @@ import org.eclipse.jgit.transport.UploadPack;
*/
public class SshTestGitServer {
+ /**
+ * Simple echo test command. Replies with the command string as passed. If
+ * of the form "echo [int] anything", takes the integer value as a delay in
+ * seconds before replying, which may be useful to test various
+ * timeout-related things.
+ *
+ * @since 5.9
+ */
+ public static final String ECHO_COMMAND = "echo";
+
@NonNull
protected final String testUser;
@@ -90,8 +104,7 @@ public class SshTestGitServer {
* @param testUser
* user name of the test user
* @param testKey
- * <em>private</em> key file of the test user; the server will
- * only user the public key from it
+ * public key file of the test user
* @param repository
* to serve
* @param hostKey
@@ -102,17 +115,54 @@ public class SshTestGitServer {
public SshTestGitServer(@NonNull String testUser, @NonNull Path testKey,
@NonNull Repository repository, @NonNull byte[] hostKey)
throws IOException, GeneralSecurityException {
+ this(testUser, readPublicKey(testKey), repository,
+ readKeyPair(hostKey));
+ }
+
+ /**
+ * Creates a ssh git <em>test</em> server. It serves one single repository,
+ * and accepts public-key authentication for exactly one test user.
+ *
+ * @param testUser
+ * user name of the test user
+ * @param testKey
+ * public key file of the test user
+ * @param repository
+ * to serve
+ * @param hostKey
+ * the unencrypted private key to use as host key
+ * @throws IOException
+ * @throws GeneralSecurityException
+ * @since 5.9
+ */
+ public SshTestGitServer(@NonNull String testUser, @NonNull Path testKey,
+ @NonNull Repository repository, @NonNull KeyPair hostKey)
+ throws IOException, GeneralSecurityException {
+ this(testUser, readPublicKey(testKey), repository, hostKey);
+ }
+
+ /**
+ * Creates a ssh git <em>test</em> server. It serves one single repository,
+ * and accepts public-key authentication for exactly one test user.
+ *
+ * @param testUser
+ * user name of the test user
+ * @param testKey
+ * the {@link PublicKey} of the test user
+ * @param repository
+ * to serve
+ * @param hostKey
+ * the {@link KeyPair} to use as host key
+ * @since 5.9
+ */
+ public SshTestGitServer(@NonNull String testUser,
+ @NonNull PublicKey testKey, @NonNull Repository repository,
+ @NonNull KeyPair hostKey) {
this.testUser = testUser;
setTestUserPublicKey(testKey);
this.repository = repository;
server = SshServer.setUpDefaultServer();
- // Set host key
- try (ByteArrayInputStream in = new ByteArrayInputStream(hostKey)) {
- SecurityUtils.loadKeyPairIdentities(null, null, in, null)
- .forEach((k) -> hostKeys.add(k));
- } catch (IOException | GeneralSecurityException e) {
- // Ignore.
- }
+ hostKeys.add(hostKey);
server.setKeyPairProvider((session) -> hostKeys);
configureAuthentication();
@@ -129,11 +179,27 @@ public class SshTestGitServer {
return new GitUploadPackCommand(command, executorService);
} else if (command.startsWith(RemoteConfig.DEFAULT_RECEIVE_PACK)) {
return new GitReceivePackCommand(command, executorService);
+ } else if (command.startsWith(ECHO_COMMAND)) {
+ return new EchoCommand(command, executorService);
}
return new UnknownCommand(command);
});
}
+ private static PublicKey readPublicKey(Path key)
+ throws IOException, GeneralSecurityException {
+ return AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
+ .resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
+ }
+
+ private static KeyPair readKeyPair(byte[] keyMaterial)
+ throws IOException, GeneralSecurityException {
+ try (ByteArrayInputStream in = new ByteArrayInputStream(keyMaterial)) {
+ return SecurityUtils.loadKeyPairIdentities(null, null, in, null)
+ .iterator().next();
+ }
+ }
+
private static class FakeUserAuthGSS extends UserAuthGSS {
@Override
protected Boolean doAuth(Buffer buffer, boolean initial)
@@ -298,6 +364,17 @@ public class SshTestGitServer {
}
/**
+ * Retrieves the server's {@link PropertyResolver}, giving access to server
+ * properties.
+ *
+ * @return the {@link PropertyResolver}
+ * @since 5.9
+ */
+ public PropertyResolver getPropertyResolver() {
+ return server;
+ }
+
+ /**
* Starts the test server, listening on a random port.
*
* @return the port the server listens on; test clients should connect to
@@ -331,8 +408,7 @@ public class SshTestGitServer {
*/
public void setTestUserPublicKey(Path key)
throws IOException, GeneralSecurityException {
- this.testKey = AuthorizedKeyEntry.readAuthorizedKeys(key).get(0)
- .resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
+ this.testKey = readPublicKey(key);
}
/**
@@ -414,4 +490,52 @@ public class SshTestGitServer {
}
}
+
+ /**
+ * Simple echo command that echoes back the command string. If the first
+ * argument is a positive integer, it's taken as a delay (in seconds) before
+ * replying. Assumes UTF-8 character encoding.
+ */
+ private static class EchoCommand extends AbstractCommandSupport {
+
+ protected EchoCommand(String command,
+ CloseableExecutorService executorService) {
+ super(command, ThreadUtils.noClose(executorService));
+ }
+
+ @Override
+ public void run() {
+ String[] parts = getCommand().split(" ");
+ int timeout = 0;
+ if (parts.length >= 2) {
+ try {
+ timeout = Integer.parseInt(parts[1]);
+ } catch (NumberFormatException e) {
+ // No timeout.
+ }
+ if (timeout > 0) {
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(timeout));
+ } catch (InterruptedException e) {
+ // Ignore.
+ }
+ }
+ }
+ try {
+ doEcho(getCommand(), getOutputStream());
+ onExit(0);
+ } catch (IOException e) {
+ log.warn(
+ MessageFormat.format("Could not run {0}", getCommand()),
+ e);
+ onExit(-1, e.toString());
+ }
+ }
+
+ private void doEcho(String text, OutputStream stream)
+ throws IOException {
+ stream.write(text.getBytes(StandardCharsets.UTF_8));
+ stream.flush();
+ }
+ }
}
diff --git a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java
index 43f9dc4b24..90d981b772 100644
--- a/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java
+++ b/org.eclipse.jgit.junit.ssh/src/org/eclipse/jgit/junit/ssh/SshTestHarness.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -9,27 +9,31 @@
*/
package org.eclipse.jgit.junit.ssh;
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import java.io.ByteArrayOutputStream;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
@@ -48,9 +52,6 @@ import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
import org.junit.After;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.KeyPair;
-
/**
* Root class for ssh tests. Sets up the ssh test server. A set of pre-computed
* keys for testing is provided in the bundle and can be used in test cases via
@@ -75,6 +76,8 @@ public abstract class SshTestHarness extends RepositoryTestCase {
protected File publicKey1;
+ protected File publicKey2;
+
protected SshTestGitServer server;
private SshSessionFactory factory;
@@ -104,50 +107,71 @@ public abstract class SshTestHarness extends RepositoryTestCase {
File serverDir = new File(getTemporaryDirectory(), "srv");
assertTrue(serverDir.mkdir());
// Create two key pairs. Let's not call them "id_rsa".
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(2048);
privateKey1 = new File(sshDir, "first_key");
privateKey2 = new File(sshDir, "second_key");
- publicKey1 = createKeyPair(privateKey1);
- createKeyPair(privateKey2);
- ByteArrayOutputStream publicHostKey = new ByteArrayOutputStream();
+ publicKey1 = createKeyPair(generator.generateKeyPair(), privateKey1);
+ publicKey2 = createKeyPair(generator.generateKeyPair(), privateKey2);
+ // Create a host key
+ KeyPair hostKey = generator.generateKeyPair();
// Start a server with our test user and the first key.
server = new SshTestGitServer(TEST_USER, publicKey1.toPath(), db,
- createHostKey(publicHostKey));
+ hostKey);
testPort = server.start();
assertTrue(testPort > 0);
knownHosts = new File(sshDir, "known_hosts");
- Files.write(knownHosts.toPath(), Collections.singleton("[localhost]:"
- + testPort + ' '
- + publicHostKey.toString(US_ASCII.name())));
+ StringBuilder knownHostsLine = new StringBuilder();
+ knownHostsLine.append("[localhost]:").append(testPort).append(' ');
+ PublicKeyEntry.appendPublicKeyEntry(knownHostsLine,
+ hostKey.getPublic());
+ Files.write(knownHosts.toPath(),
+ Collections.singleton(knownHostsLine.toString()));
factory = createSessionFactory();
SshSessionFactory.setInstance(factory);
}
- private static File createKeyPair(File privateKeyFile) throws Exception {
- // Found no way to do this with MINA sshd except rolling it all
- // ourselves...
- JSch jsch = new JSch();
- KeyPair pair = KeyPair.genKeyPair(jsch, KeyPair.RSA, 2048);
- try (OutputStream out = new FileOutputStream(privateKeyFile)) {
- pair.writePrivateKey(out);
+ private static File createKeyPair(KeyPair newKey, File privateKeyFile)
+ throws Exception {
+ // Write PKCS#8 PEM unencrypted. Both JSch and sshd can read that.
+ PrivateKey privateKey = newKey.getPrivate();
+ String format = privateKey.getFormat();
+ if (!"PKCS#8".equalsIgnoreCase(format)) {
+ throw new IOException("Cannot write " + privateKey.getAlgorithm()
+ + " key in " + format + " format");
+ }
+ try (BufferedWriter writer = Files.newBufferedWriter(
+ privateKeyFile.toPath(), StandardCharsets.US_ASCII)) {
+ writer.write("-----BEGIN PRIVATE KEY-----");
+ writer.newLine();
+ write(writer, privateKey.getEncoded(), 64);
+ writer.write("-----END PRIVATE KEY-----");
+ writer.newLine();
}
File publicKeyFile = new File(privateKeyFile.getParentFile(),
privateKeyFile.getName() + ".pub");
+ StringBuilder builder = new StringBuilder();
+ PublicKeyEntry.appendPublicKeyEntry(builder, newKey.getPublic());
+ builder.append(' ').append(TEST_USER);
try (OutputStream out = new FileOutputStream(publicKeyFile)) {
- pair.writePublicKey(out, TEST_USER);
+ out.write(builder.toString().getBytes(StandardCharsets.US_ASCII));
}
return publicKeyFile;
}
- private static byte[] createHostKey(OutputStream publicKey)
- throws Exception {
- JSch jsch = new JSch();
- KeyPair pair = KeyPair.genKeyPair(jsch, KeyPair.RSA, 2048);
- pair.writePublicKey(publicKey, "");
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- pair.writePrivateKey(out);
- out.flush();
- return out.toByteArray();
+ private static void write(BufferedWriter out, byte[] bytes, int lineLength)
+ throws IOException {
+ String data = Base64.getEncoder().encodeToString(bytes);
+ int last = data.length();
+ for (int i = 0; i < last; i += lineLength) {
+ if (i + lineLength <= last) {
+ out.write(data.substring(i, i + lineLength));
+ } else {
+ out.write(data.substring(i));
+ }
+ out.newLine();
}
+ Arrays.fill(bytes, (byte) 0);
}
/**
@@ -167,7 +191,8 @@ public abstract class SshTestHarness extends RepositoryTestCase {
*/
protected static String createKnownHostsFile(File file, String host,
int port, File publicKey) throws IOException {
- List<String> lines = Files.readAllLines(publicKey.toPath(), UTF_8);
+ List<String> lines = Files.readAllLines(publicKey.toPath(),
+ StandardCharsets.UTF_8);
assertEquals("Public key has too many lines", 1, lines.size());
String pubKey = lines.get(0);
// Strip off the comment.
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index de11e2c004..64556acc1c 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -34,6 +34,7 @@ import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
@@ -45,6 +46,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
+import org.junit.After;
import org.junit.Before;
/**
@@ -186,6 +188,13 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
trash = db.getWorkTree();
}
+ @Override
+ @After
+ public void tearDown() throws Exception {
+ db.close();
+ super.tearDown();
+ }
+
/**
* Represent the state of the index in one String. This representation is
* useful when writing tests which do assertions on the state of the index.
@@ -513,6 +522,21 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
}
/**
+ * Create <code>DirCacheEntry</code>
+ *
+ * @param path
+ * @param objectId
+ * @return the DirCacheEntry
+ */
+ protected DirCacheEntry createGitLink(String path, AnyObjectId objectId) {
+ final DirCacheEntry entry = new DirCacheEntry(path,
+ DirCacheEntry.STAGE_0);
+ entry.setFileMode(FileMode.GITLINK);
+ entry.setObjectId(objectId);
+ return entry;
+ }
+
+ /**
* Assert files are equal
*
* @param expected
diff --git a/org.eclipse.jgit.lfs.test/BUILD b/org.eclipse.jgit.lfs.test/BUILD
index 061ecd71f7..4665f675b1 100644
--- a/org.eclipse.jgit.lfs.test/BUILD
+++ b/org.eclipse.jgit.lfs.test/BUILD
@@ -13,6 +13,7 @@ junit_tests(
deps = [
":helpers",
"//lib:junit",
+ "//lib:slf4j-api",
"//org.eclipse.jgit:jgit",
"//org.eclipse.jgit.junit:junit",
"//org.eclipse.jgit.lfs:jgit-lfs",
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
index cbad1b66a9..7a0ed456c1 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java
@@ -112,8 +112,8 @@ public class LfsConnectionFactory {
remoteUrl = config.getString(
ConfigConstants.CONFIG_KEY_REMOTE, remote,
ConfigConstants.CONFIG_KEY_URL);
+ break;
}
- break;
}
if (lfsUrl == null && remoteUrl != null) {
try {
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
index 452503a330..931e196cf6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.10" sequenceNumber="1590935844">
+<target name="jgit-4.10" sequenceNumber="1605866255">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
index 717bc0a090..b87917b8ab 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd
@@ -1,7 +1,7 @@
target "jgit-4.10" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2018-12/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
index 03e3641d65..8090999601 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.11" sequenceNumber="1590935852">
+<target name="jgit-4.11" sequenceNumber="1605866333">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
index 9abd9b2d3c..844a1d791f 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd
@@ -1,7 +1,7 @@
target "jgit-4.11" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2019-03/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
index 2c09a1770c..69eb639726 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.12" sequenceNumber="1590935859">
+<target name="jgit-4.12" sequenceNumber="1605866333">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
index e668a9df80..afbf79d531 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd
@@ -1,7 +1,7 @@
target "jgit-4.12" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2019-06/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
index b92beb48b9..fdbed2d2a4 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.13" sequenceNumber="1590935871">
+<target name="jgit-4.13" sequenceNumber="1605866333">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.13.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
index 0499e3f163..d83e338460 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd
@@ -1,7 +1,7 @@
target "jgit-4.13" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2019-09/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
index 6ab40f0427..c2ef9d24a1 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.14-staging" sequenceNumber="1590935878">
+<target name="jgit-4.14" sequenceNumber="1605866331">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.14.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
index c2fa119d1a..f357ccd24c 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14.tpd
@@ -1,7 +1,7 @@
-target "jgit-4.14-staging" with source configurePhase
+target "jgit-4.14" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2019-12/201912181000/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
index a7ca0dc72a..4034d2a362 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.15" sequenceNumber="1590935883">
+<target name="jgit-4.15" sequenceNumber="1605866331">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.15.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
index ff55a7d966..881fe37e73 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.15.tpd
@@ -1,7 +1,7 @@
target "jgit-4.15" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2020-03/202003181000/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16-staging.tpd
deleted file mode 100644
index 777aaf3ce2..0000000000
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16-staging.tpd
+++ /dev/null
@@ -1,8 +0,0 @@
-target "jgit-4.15" with source configurePhase
-
-include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
-
-location "https://download.eclipse.org/staging/2020-06/" {
- org.eclipse.osgi lazy
-}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
new file mode 100644
index 0000000000..34d872cdd5
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.target
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
+<target name="jgit-4.16" sequenceNumber="1605866333">
+ <locations>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
+ </location>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
+ <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+ <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="javaewah" version="1.1.7.v20200107-0831"/>
+ <unit id="javaewah.source" version="1.1.7.v20200107-0831"/>
+ <unit id="javax.servlet" version="3.1.0.v201410161800"/>
+ <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
+ <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.v20181102-1323"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
+ <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
+ <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.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+ <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
+ <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+ <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
+ <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+ <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
+ <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
+ <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcprov" version="1.65.1.v20200529-1514"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.65.1.v20200529-1514"/>
+ <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+ <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.0.v20200204-1500"/>
+ <unit id="org.junit.source" version="4.13.0.v20200204-1500"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
+ <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+ <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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/2020-06/"/>
+ </location>
+ </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
new file mode 100644
index 0000000000..9a07597119
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.16" with source configurePhase
+
+include "projects/jetty-9.4.x.tpd"
+include "orbit/S20201118210000.tpd"
+
+location "https://download.eclipse.org/releases/2020-06/" {
+ org.eclipse.osgi lazy
+}
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
new file mode 100644
index 0000000000..3384c23563
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target
@@ -0,0 +1,94 @@
+<?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="1605866541">
+ <locations>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
+ </location>
+ <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+ <unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
+ <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/>
+ <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="javaewah" version="1.1.7.v20200107-0831"/>
+ <unit id="javaewah.source" version="1.1.7.v20200107-0831"/>
+ <unit id="javax.servlet" version="3.1.0.v201410161800"/>
+ <unit id="javax.servlet.source" version="3.1.0.v201410161800"/>
+ <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.v20181102-1323"/>
+ <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
+ <unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
+ <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.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
+ <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
+ <unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
+ <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/>
+ <unit id="org.apache.sshd.osgi" version="2.4.0.v20200318-1614"/>
+ <unit id="org.apache.sshd.osgi.source" version="2.4.0.v20200318-1614"/>
+ <unit id="org.apache.sshd.sftp" version="2.4.0.v20200319-1547"/>
+ <unit id="org.apache.sshd.sftp.source" version="2.4.0.v20200319-1547"/>
+ <unit id="org.assertj" version="3.14.0.v20200120-1926"/>
+ <unit id="org.assertj.source" version="3.14.0.v20200120-1926"/>
+ <unit id="org.bouncycastle.bcpg" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcpg.source" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcpkix" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcpkix.source" version="1.65.0.v20200527-1955"/>
+ <unit id="org.bouncycastle.bcprov" version="1.65.1.v20200529-1514"/>
+ <unit id="org.bouncycastle.bcprov.source" version="1.65.1.v20200529-1514"/>
+ <unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
+ <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.0.v20200204-1500"/>
+ <unit id="org.junit.source" version="4.13.0.v20200204-1500"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
+ <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
+ <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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/2020-09/"/>
+ </location>
+ </locations>
+</target>
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
new file mode 100644
index 0000000000..ce79cf45e8
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.17" with source configurePhase
+
+include "projects/jetty-9.4.x.tpd"
+include "orbit/S20201118210000.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.16-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.target
index 0aff7968e2..5eeab9534a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.16-staging.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.15" sequenceNumber="1590935890">
+<target name="jgit-4.18-staging" sequenceNumber="1605866541">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,17 +78,17 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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/2020-06/"/>
+ <repository location="https://download.eclipse.org/staging/2020-12/"/>
</location>
</locations>
</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.tpd
new file mode 100644
index 0000000000..0669490bb0
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18-staging.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.18-staging" with source configurePhase
+
+include "projects/jetty-9.4.x.tpd"
+include "orbit/S20201118210000.tpd"
+
+location "https://download.eclipse.org/staging/2020-12/" {
+ org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
index b07ddd0058..a66fcc0821 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.6" sequenceNumber="1590935806">
+<target name="jgit-4.6" sequenceNumber="1605866347">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/repository"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
index d0c3c1bcfc..aa58b68577 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd
@@ -1,7 +1,7 @@
target "jgit-4.6" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/neon/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
index 351b0fc0e1..4b5410a3d7 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.7" sequenceNumber="1590935820">
+<target name="jgit-4.7" sequenceNumber="1605866338">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/repository"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
index 19790ff0ac..e2264e0038 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd
@@ -1,7 +1,7 @@
target "jgit-4.7" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/oxygen/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
index be6108d489..d776427455 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.8" sequenceNumber="1590935828">
+<target name="jgit-4.8" sequenceNumber="1605866333">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
index 5fe27fcf62..c92ce53963 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd
@@ -1,7 +1,7 @@
target "jgit-4.8" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/photon/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
index b9ad2cbacb..56002b78a8 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?>
<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.9" sequenceNumber="1590935836">
+<target name="jgit-4.9" sequenceNumber="1605866333">
<locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
- <unit id="org.eclipse.jetty.client" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.client.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.continuation.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.http.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.io.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.security.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.server.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.servlet.source" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util" version="9.4.28.v20200408"/>
- <unit id="org.eclipse.jetty.util.source" version="9.4.28.v20200408"/>
- <repository id="jetty-9.4.25" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/"/>
+ <unit id="org.eclipse.jetty.client" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.client.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.continuation.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.http.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.io.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.security.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.server.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.servlet.source" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util" version="9.4.30.v20200611"/>
+ <unit id="org.eclipse.jetty.util.source" version="9.4.30.v20200611"/>
+ <repository id="jetty-9.4.30" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/"/>
</location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="com.google.gson" version="2.8.2.v20180104-1110"/>
@@ -39,16 +39,16 @@
<unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/>
<unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/>
<unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/>
- <unit id="org.apache.ant" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.ant.source" version="1.10.8.v20200515-1239"/>
- <unit id="org.apache.commons.codec" version="1.13.0.v20200108-0001"/>
- <unit id="org.apache.commons.codec.source" version="1.13.0.v20200108-0001"/>
+ <unit id="org.apache.ant" version="1.10.9.v20201106-1946"/>
+ <unit id="org.apache.ant.source" version="1.10.9.v20201106-1946"/>
+ <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.19.0.v20200106-2343"/>
<unit id="org.apache.commons.compress.source" version="1.19.0.v20200106-2343"/>
<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.10.v20200114-1512"/>
- <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200114-1512"/>
+ <unit id="org.apache.httpcomponents.httpclient" version="4.5.10.v20200830-2311"/>
+ <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.10.v20200830-2311"/>
<unit id="org.apache.httpcomponents.httpcore" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.httpcomponents.httpcore.source" version="4.4.12.v20200108-1212"/>
<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
@@ -78,13 +78,13 @@
<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.2.v20121108-1250"/>
- <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
- <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
- <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
+ <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.log4j12" version="1.7.30.v20201108-2042"/>
+ <unit id="org.slf4j.binding.log4j12.source" version="1.7.30.v20201108-2042"/>
<unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/>
<unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/>
- <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20200529191137/repository"/>
+ <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/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.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
index 4e39322b15..06ccecbd5d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
@@ -1,7 +1,7 @@
target "jgit-4.9" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20200529191137-2020-06.tpd"
+include "orbit/S20201118210000.tpd"
location "https://download.eclipse.org/releases/2018-09/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20200519202422.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20200831200620-2020-09.tpd
index abe97e1fd3..22e2b01207 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20200519202422.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20200831200620-2020-09.tpd
@@ -1,7 +1,7 @@
-target "S20200519202422" with source configurePhase
+target "R20200831200620-2020-09" with source configurePhase
// see https://download.eclipse.org/tools/orbit/downloads/
-location "https://download.eclipse.org/tools/orbit/downloads/drops/S20200519202422/repository" {
+location "https://download.eclipse.org/tools/orbit/downloads/drops/R20200831200620/repository" {
com.google.gson [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
com.google.gson.source [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
@@ -20,14 +20,14 @@ location "https://download.eclipse.org/tools/orbit/downloads/drops/S202005192024
net.i2p.crypto.eddsa.source [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
org.apache.ant [1.10.8.v20200515-1239,1.10.8.v20200515-1239]
org.apache.ant.source [1.10.8.v20200515-1239,1.10.8.v20200515-1239]
- org.apache.commons.codec [1.13.0.v20200108-0001,1.13.0.v20200108-0001]
- org.apache.commons.codec.source [1.13.0.v20200108-0001,1.13.0.v20200108-0001]
+ 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.19.0.v20200106-2343,1.19.0.v20200106-2343]
org.apache.commons.compress.source [1.19.0.v20200106-2343,1.19.0.v20200106-2343]
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.10.v20200114-1512,4.5.10.v20200114-1512]
- org.apache.httpcomponents.httpclient.source [4.5.10.v20200114-1512,4.5.10.v20200114-1512]
+ org.apache.httpcomponents.httpclient [4.5.10.v20200830-2311,4.5.10.v20200830-2311]
+ org.apache.httpcomponents.httpclient.source [4.5.10.v20200830-2311,4.5.10.v20200830-2311]
org.apache.httpcomponents.httpcore [4.4.12.v20200108-1212,4.4.12.v20200108-1212]
org.apache.httpcomponents.httpcore.source [4.4.12.v20200108-1212,4.4.12.v20200108-1212]
org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
@@ -38,12 +38,12 @@ location "https://download.eclipse.org/tools/orbit/downloads/drops/S202005192024
org.apache.sshd.sftp.source [2.4.0.v20200319-1547,2.4.0.v20200319-1547]
org.assertj [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
org.assertj.source [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
- org.bouncycastle.bcpg [1.65.0.v20200502-2229,1.65.0.v20200502-2229]
- org.bouncycastle.bcpg.source [1.65.0.v20200502-2229,1.65.0.v20200502-2229]
- org.bouncycastle.bcpkix [1.65.0.v20200502-2229,1.65.0.v20200502-2229]
- org.bouncycastle.bcpkix.source [1.65.0.v20200502-2229,1.65.0.v20200502-2229]
- org.bouncycastle.bcprov [1.65.0.v20200502-2229,1.65.0.v20200502-2229]
- org.bouncycastle.bcprov.source [1.65.0.v20200502-2229,1.65.0.v20200502-2229]
+ org.bouncycastle.bcpg [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcpg.source [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcpkix [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcpkix.source [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcprov [1.65.1.v20200529-1514,1.65.1.v20200529-1514]
+ org.bouncycastle.bcprov.source [1.65.1.v20200529-1514,1.65.1.v20200529-1514]
org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000]
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]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20201118210000.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20201118210000.tpd
new file mode 100644
index 0000000000..a00a5e7c87
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20201118210000.tpd
@@ -0,0 +1,66 @@
+target "S20201118210000" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/downloads/drops/S20201118210000/repository" {
+ com.google.gson [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
+ com.google.gson.source [2.8.2.v20180104-1110,2.8.2.v20180104-1110]
+ com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+ com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+ com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+ com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
+ javaewah [1.1.7.v20200107-0831,1.1.7.v20200107-0831]
+ javaewah.source [1.1.7.v20200107-0831,1.1.7.v20200107-0831]
+ javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
+ javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
+ 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.v20181102-1323,0.3.0.v20181102-1323]
+ net.i2p.crypto.eddsa.source [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+ org.apache.ant [1.10.9.v20201106-1946,1.10.9.v20201106-1946]
+ org.apache.ant.source [1.10.9.v20201106-1946,1.10.9.v20201106-1946]
+ 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.19.0.v20200106-2343,1.19.0.v20200106-2343]
+ org.apache.commons.compress.source [1.19.0.v20200106-2343,1.19.0.v20200106-2343]
+ 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.10.v20200830-2311,4.5.10.v20200830-2311]
+ org.apache.httpcomponents.httpclient.source [4.5.10.v20200830-2311,4.5.10.v20200830-2311]
+ org.apache.httpcomponents.httpcore [4.4.12.v20200108-1212,4.4.12.v20200108-1212]
+ org.apache.httpcomponents.httpcore.source [4.4.12.v20200108-1212,4.4.12.v20200108-1212]
+ org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
+ org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+ org.apache.sshd.osgi [2.4.0.v20200318-1614,2.4.0.v20200318-1614]
+ org.apache.sshd.osgi.source [2.4.0.v20200318-1614,2.4.0.v20200318-1614]
+ org.apache.sshd.sftp [2.4.0.v20200319-1547,2.4.0.v20200319-1547]
+ org.apache.sshd.sftp.source [2.4.0.v20200319-1547,2.4.0.v20200319-1547]
+ org.assertj [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
+ org.assertj.source [3.14.0.v20200120-1926,3.14.0.v20200120-1926]
+ org.bouncycastle.bcpg [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcpg.source [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcpkix [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcpkix.source [1.65.0.v20200527-1955,1.65.0.v20200527-1955]
+ org.bouncycastle.bcprov [1.65.1.v20200529-1514,1.65.1.v20200529-1514]
+ org.bouncycastle.bcprov.source [1.65.1.v20200529-1514,1.65.1.v20200529-1514]
+ org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000]
+ 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.0.v20200204-1500,4.13.0.v20200204-1500]
+ org.junit.source [4.13.0.v20200204-1500,4.13.0.v20200204-1500]
+ 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.log4j12 [1.7.30.v20201108-2042,1.7.30.v20201108-2042]
+ org.slf4j.binding.log4j12.source [1.7.30.v20201108-2042,1.7.30.v20201108-2042]
+ org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+ org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613]
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
index 0eea06d64c..70c426c188 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
@@ -1,20 +1,20 @@
target "jetty-9.4.x" with source configurePhase
-location jetty-9.4.25 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.28.v20200408/" {
- org.eclipse.jetty.client [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.client.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.continuation [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.continuation.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.http [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.http.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.io [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.io.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.security [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.security.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.server [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.server.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.servlet [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.servlet.source [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.util [9.4.28.v20200408,9.4.28.v20200408]
- org.eclipse.jetty.util.source [9.4.28.v20200408,9.4.28.v20200408]
+location jetty-9.4.30 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.30.v20200611/" {
+ org.eclipse.jetty.client [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.client.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.continuation [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.continuation.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.http [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.http.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.io [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.io.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.security [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.security.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.server [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.server.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.servlet [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.servlet.source [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.util [9.4.30.v20200611,9.4.30.v20200611]
+ org.eclipse.jetty.util.source [9.4.30.v20200611,9.4.30.v20200611]
}
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index c106f8756f..165854d21e 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -212,7 +212,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
- <version>3.1.0</version>
+ <version>3.2.0</version>
<configuration>
<encoding>ISO-8859-1</encoding>
</configuration>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
index 4ecaeb604a..46eec7436e 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
@@ -33,7 +33,7 @@ public class LsRemoteTest extends CLIRepositoryTestCase {
git.add().addFilepattern("Test.txt").call();
git.commit().setMessage("Initial commit").call();
- // create a master branch and switch to it
+ // create a test branch and switch to it
git.branchCreate().setName("test").call();
RefUpdate rup = db.updateRef(Constants.HEAD);
rup.link("refs/heads/test");
@@ -104,4 +104,22 @@ public class LsRemoteTest extends CLIRepositoryTestCase {
"" }, result.toArray());
}
+ @Test
+ public void testLsRemoteSymRefs() throws Exception {
+ final List<String> result = CLIGitCommand.execute(
+ "git ls-remote --symref " + shellQuote(db.getDirectory()), db);
+ assertArrayEquals(new String[] {
+ "ref: refs/heads/test HEAD",
+ "d0b1ef2b3dea02bb2ca824445c04e6def012c32c HEAD",
+ "d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/master",
+ "d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/heads/test",
+ "efc02078d83a5226986ae917323acec7e1e8b7cb refs/tags/tag1",
+ "d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/tags/tag1^{}",
+ "4e4b837e0fd4ba83c003678b03592dc1509a4115 refs/tags/tag2",
+ "d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/tags/tag2^{}",
+ "489384bf8ace47522fe32093d2ceb85b65a6cbb1 refs/tags/tag3",
+ "d0b1ef2b3dea02bb2ca824445c04e6def012c32c refs/tags/tag3^{}",
+ "" }, result.toArray());
+ }
+
}
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 f3e1fe31ba..6112a272e4 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
@@ -256,6 +256,7 @@ usage_LsFiles=Show information about files in the index and the working tree
usage_LsRemote=List references in a remote repository
usage_lsRemoteHeads=Show only refs starting with refs/heads
usage_lsRemoteTags=Show only refs starting with refs/tags
+usage_lsRemoteSymref=In addition to the object pointed at, show the underlying ref pointed at when showing a symbolic ref.
usage_LsTree=List the contents of a tree object
usage_MakeCacheTree=Show the current cache tree structure
usage_Match=Only consider tags matching the given glob(7) pattern or patterns, excluding the "refs/tags/" prefix.
@@ -294,6 +295,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_UpdateRemoteRepositoryFromLocalRefs=Update remote repository from local refs
+usage_UseAll=Use all refs found in refs/
usage_UseTags=Use any tag including lightweight tags
usage_WriteDirCache=Write the DirCache
usage_abbrevCommits=abbreviate commits to N + 1 digits
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
index 610b6472a5..8aa119a358 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -32,6 +32,9 @@ class Describe extends TextBuiltin {
@Option(name = "--long", usage = "usage_LongFormat")
private boolean longDesc;
+ @Option(name = "--all", usage = "usage_UseTags")
+ private boolean useAll;
+
@Option(name = "--tags", usage = "usage_UseTags")
private boolean useTags;
@@ -50,6 +53,7 @@ class Describe extends TextBuiltin {
cmd.setTarget(tree);
}
cmd.setLong(longDesc);
+ cmd.setAll(useAll);
cmd.setTags(useTags);
cmd.setAlways(always);
cmd.setMatch(patterns.toArray(new String[0]));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
index 36812c03a4..055b48a157 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/LsRemote.java
@@ -34,6 +34,9 @@ class LsRemote extends TextBuiltin {
@Option(name = "--timeout", metaVar = "metaVar_service", usage = "usage_abortConnectionIfNoActivity")
int timeout = -1;
+ @Option(name = "--symref", usage = "usage_lsRemoteSymref")
+ private boolean symref;
+
@Argument(index = 0, metaVar = "metaVar_uriish", required = true)
private String remote;
@@ -47,6 +50,9 @@ class LsRemote extends TextBuiltin {
try {
refs.addAll(command.call());
for (Ref r : refs) {
+ if (symref && r.isSymbolic()) {
+ show(r.getTarget(), r.getName());
+ }
show(r.getObjectId(), r.getName());
if (r.getPeeledObjectId() != null) {
show(r.getPeeledObjectId(), r.getName() + "^{}"); //$NON-NLS-1$
@@ -70,4 +76,13 @@ class LsRemote extends TextBuiltin {
outw.print(name);
outw.println();
}
+
+ private void show(Ref ref, String name)
+ throws IOException {
+ outw.print("ref: ");
+ outw.print(ref.getName());
+ outw.print('\t');
+ outw.print(name);
+ outw.println();
+ }
}
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 635ff75428..fe3a2616f3 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -15,6 +15,9 @@ Import-Package: org.apache.sshd.client.config.hosts;version="[2.4.0,2.5.0)",
org.apache.sshd.common.session;version="[2.4.0,2.5.0)",
org.apache.sshd.common.util.net;version="[2.4.0,2.5.0)",
org.apache.sshd.common.util.security;version="[2.4.0,2.5.0)",
+ org.apache.sshd.server;version="[2.4.0,2.5.0)",
+ org.apache.sshd.server.forward;version="[2.4.0,2.5.0)",
+ org.eclipse.jgit.api;version="[6.0.0,6.1.0)",
org.eclipse.jgit.api.errors;version="[6.0.0,6.1.0)",
org.eclipse.jgit.internal.transport.sshd.proxy;version="[6.0.0,6.1.0)",
org.eclipse.jgit.junit;version="[6.0.0,6.1.0)",
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 bfee04219d..3427da667d 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, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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,16 +11,40 @@ package org.eclipse.jgit.transport.sshd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
+
import org.apache.sshd.client.config.hosts.KnownHostEntry;
+import org.apache.sshd.client.config.hosts.KnownHostHashValue;
+import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.PublicKeyEntry;
+import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.server.ServerAuthenticationManager;
+import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.forward.StaticDecisionForwardingFilter;
+import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.junit.ssh.SshTestBase;
import org.eclipse.jgit.lib.Constants;
@@ -156,7 +180,7 @@ public class ApacheSshTest extends SshTestBase {
"IdentityFile " + privateKey1.getAbsolutePath());
}
- @Test (expected = TransportException.class)
+ @Test
public void testHugePreamble() throws Exception {
// Test that the connection fails when the preamble is longer than 64k.
StringBuilder b = new StringBuilder();
@@ -169,10 +193,418 @@ public class ApacheSshTest extends SshTestBase {
lines[i] = line;
}
server.setPreamble(lines);
- cloneWith(
- "ssh://" + TEST_USER + "@localhost:" + testPort
- + "/doesntmatter",
- defaultCloneDir, null,
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith(
+ "ssh://" + TEST_USER + "@localhost:" + testPort
+ + "/doesntmatter",
+ defaultCloneDir, null,
+ "IdentityFile " + privateKey1.getAbsolutePath()));
+ // The assertions test that we don't run into bug 565394 / SSHD-1050
+ assertFalse(e.getMessage().contains("timeout"));
+ assertTrue(e.getMessage().contains("65536")
+ || e.getMessage().contains("closed"));
+ }
+
+ /**
+ * Test for SSHD-1028. If the server doesn't close sessions, the second
+ * fetch will fail. Occurs on sshd 2.5.[01].
+ *
+ * @throws Exception
+ * on errors
+ * @see <a href=
+ * "https://issues.apache.org/jira/projects/SSHD/issues/SSHD-1028">SSHD-1028</a>
+ */
+ @Test
+ public void testCloneAndFetchWithSessionLimit() throws Exception {
+ PropertyResolverUtils.updateProperty(server.getPropertyResolver(),
+ ServerFactoryManager.MAX_CONCURRENT_SESSIONS, 2);
+ File localClone = cloneWith("ssh://localhost/doesntmatter",
+ defaultCloneDir, null, //
+ "Host localhost", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
"IdentityFile " + privateKey1.getAbsolutePath());
+ // Fetch a couple of times
+ try (Git git = Git.open(localClone)) {
+ git.fetch().call();
+ git.fetch().call();
+ }
+ }
+
+ /**
+ * Creates a simple proxy server. Accepts only publickey authentication from
+ * the given user with the given key, allows all forwardings. Adds the
+ * proxy's host key to {@link #knownHosts}.
+ *
+ * @param user
+ * to accept
+ * @param userKey
+ * public key of that user at this server
+ * @param report
+ * single-element array to report back the forwarded address.
+ * @return the started server
+ * @throws Exception
+ */
+ private SshServer createProxy(String user, File userKey,
+ SshdSocketAddress[] report) throws Exception {
+ SshServer proxy = SshServer.setUpDefaultServer();
+ // Give the server its own host key
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(2048);
+ KeyPair proxyHostKey = generator.generateKeyPair();
+ proxy.setKeyPairProvider(
+ session -> Collections.singletonList(proxyHostKey));
+ // Allow (only) publickey authentication
+ proxy.setUserAuthFactories(Collections.singletonList(
+ ServerAuthenticationManager.DEFAULT_USER_AUTH_PUBLIC_KEY_FACTORY));
+ // Install the user's public key
+ PublicKey userProxyKey = AuthorizedKeyEntry
+ .readAuthorizedKeys(userKey.toPath()).get(0)
+ .resolvePublicKey(null, PublicKeyEntryResolver.IGNORING);
+ proxy.setPublickeyAuthenticator(
+ (userName, publicKey, session) -> user.equals(userName)
+ && KeyUtils.compareKeys(userProxyKey, publicKey));
+ // Allow forwarding
+ proxy.setForwardingFilter(new StaticDecisionForwardingFilter(true) {
+
+ @Override
+ protected boolean checkAcceptance(String request, Session session,
+ SshdSocketAddress target) {
+ report[0] = target;
+ return super.checkAcceptance(request, session, target);
+ }
+ });
+ proxy.start();
+ // Add the proxy's host key to knownhosts
+ try (BufferedWriter writer = Files.newBufferedWriter(
+ knownHosts.toPath(), StandardCharsets.US_ASCII,
+ StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
+ writer.append('\n');
+ KnownHostHashValue.appendHostPattern(writer, "localhost",
+ proxy.getPort());
+ writer.append(',');
+ KnownHostHashValue.appendHostPattern(writer, "127.0.0.1",
+ proxy.getPort());
+ writer.append(' ');
+ PublicKeyEntry.appendPublicKeyEntry(writer,
+ proxyHostKey.getPublic());
+ writer.append('\n');
+ }
+ return proxy;
+ }
+
+ @Test
+ public void testJumpHost() throws Exception {
+ SshdSocketAddress[] forwarded = { null };
+ try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded)) {
+ try {
+ // Now try to clone via the proxy
+ cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump " + TEST_USER + "X@proxy:" + proxy.getPort(), //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "IdentityFile " + privateKey2.getAbsolutePath());
+ assertNotNull(forwarded[0]);
+ assertEquals(testPort, forwarded[0].getPort());
+ } finally {
+ proxy.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostWrongKeyAtProxy() throws Exception {
+ // Test that we find the proxy server's URI in the exception message
+ SshdSocketAddress[] forwarded = { null };
+ try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded)) {
+ try {
+ // Now try to clone via the proxy
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://server/doesntmatter",
+ defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(),
+ "ProxyJump " + TEST_USER + "X@proxy:"
+ + proxy.getPort(), //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "IdentityFile "
+ + privateKey1.getAbsolutePath()));
+ String message = e.getMessage();
+ assertTrue(message.contains("localhost:" + proxy.getPort()));
+ assertTrue(message.contains("proxy:" + proxy.getPort()));
+ } finally {
+ proxy.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostWrongKeyAtServer() throws Exception {
+ // Test that we find the target server's URI in the exception message
+ SshdSocketAddress[] forwarded = { null };
+ try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded)) {
+ try {
+ // Now try to clone via the proxy
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://server/doesntmatter",
+ defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey2.getAbsolutePath(),
+ "ProxyJump " + TEST_USER + "X@proxy:"
+ + proxy.getPort(), //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "IdentityFile "
+ + privateKey2.getAbsolutePath()));
+ String message = e.getMessage();
+ assertTrue(message.contains("localhost:" + testPort));
+ assertTrue(message.contains("ssh://server"));
+ } finally {
+ proxy.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostNonSsh() throws Exception {
+ SshdSocketAddress[] forwarded = { null };
+ try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded)) {
+ try {
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://server/doesntmatter",
+ defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump http://" + TEST_USER + "X@proxy:"
+ + proxy.getPort(), //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "IdentityFile "
+ + privateKey2.getAbsolutePath()));
+ // Find the expected message
+ Throwable t = e;
+ while (t != null) {
+ if (t instanceof URISyntaxException) {
+ break;
+ }
+ t = t.getCause();
+ }
+ assertNotNull(t);
+ assertTrue(t.getMessage().contains("Non-ssh"));
+ } finally {
+ proxy.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostWithPath() throws Exception {
+ SshdSocketAddress[] forwarded = { null };
+ try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded)) {
+ try {
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://server/doesntmatter",
+ defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump ssh://" + TEST_USER + "X@proxy:"
+ + proxy.getPort() + "/wrongPath", //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "IdentityFile "
+ + privateKey2.getAbsolutePath()));
+ // Find the expected message
+ Throwable t = e;
+ while (t != null) {
+ if (t instanceof URISyntaxException) {
+ break;
+ }
+ t = t.getCause();
+ }
+ assertNotNull(t);
+ assertTrue(t.getMessage().contains("wrongPath"));
+ } finally {
+ proxy.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostWithPathShort() throws Exception {
+ SshdSocketAddress[] forwarded = { null };
+ try (SshServer proxy = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded)) {
+ try {
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith("ssh://server/doesntmatter",
+ defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump " + TEST_USER + "X@proxy:wrongPath", //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "Port " + proxy.getPort(), //
+ "IdentityFile "
+ + privateKey2.getAbsolutePath()));
+ // Find the expected message
+ Throwable t = e;
+ while (t != null) {
+ if (t instanceof URISyntaxException) {
+ break;
+ }
+ t = t.getCause();
+ }
+ assertNotNull(t);
+ assertTrue(t.getMessage().contains("wrongPath"));
+ } finally {
+ proxy.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostChain() throws Exception {
+ SshdSocketAddress[] forwarded1 = { null };
+ SshdSocketAddress[] forwarded2 = { null };
+ try (SshServer proxy1 = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded1);
+ SshServer proxy2 = createProxy("foo", publicKey1, forwarded2)) {
+ try {
+ // Clone proxy1 -> proxy2 -> server
+ cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump proxy2," + TEST_USER + "X@proxy:"
+ + proxy1.getPort(), //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "IdentityFile " + privateKey2.getAbsolutePath(), //
+ "", //
+ "Host proxy2", //
+ "Hostname localhost", //
+ "User foo", //
+ "Port " + proxy2.getPort(), //
+ "IdentityFile " + privateKey1.getAbsolutePath());
+ assertNotNull(forwarded1[0]);
+ assertEquals(proxy2.getPort(), forwarded1[0].getPort());
+ assertNotNull(forwarded2[0]);
+ assertEquals(testPort, forwarded2[0].getPort());
+ } finally {
+ proxy1.stop();
+ proxy2.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostCascade() throws Exception {
+ SshdSocketAddress[] forwarded1 = { null };
+ SshdSocketAddress[] forwarded2 = { null };
+ try (SshServer proxy1 = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded1);
+ SshServer proxy2 = createProxy("foo", publicKey1, forwarded2)) {
+ try {
+ // Clone proxy2 -> proxy1 -> server
+ cloneWith("ssh://server/doesntmatter", defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump " + TEST_USER + "X@proxy", //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "Port " + proxy1.getPort(), //
+ "ProxyJump ssh://proxy2:" + proxy2.getPort(), //
+ "IdentityFile " + privateKey2.getAbsolutePath(), //
+ "", //
+ "Host proxy2", //
+ "Hostname localhost", //
+ "User foo", //
+ "IdentityFile " + privateKey1.getAbsolutePath());
+ assertNotNull(forwarded1[0]);
+ assertEquals(testPort, forwarded1[0].getPort());
+ assertNotNull(forwarded2[0]);
+ assertEquals(proxy1.getPort(), forwarded2[0].getPort());
+ } finally {
+ proxy1.stop();
+ proxy2.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testJumpHostRecursion() throws Exception {
+ SshdSocketAddress[] forwarded1 = { null };
+ SshdSocketAddress[] forwarded2 = { null };
+ try (SshServer proxy1 = createProxy(TEST_USER + 'X', publicKey2,
+ forwarded1);
+ SshServer proxy2 = createProxy("foo", publicKey1, forwarded2)) {
+ try {
+ TransportException e = assertThrows(TransportException.class,
+ () -> cloneWith(
+ "ssh://server/doesntmatter", defaultCloneDir, null, //
+ "Host server", //
+ "HostName localhost", //
+ "Port " + testPort, //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "ProxyJump " + TEST_USER + "X@proxy", //
+ "", //
+ "Host proxy", //
+ "Hostname localhost", //
+ "Port " + proxy1.getPort(), //
+ "ProxyJump ssh://proxy2:" + proxy2.getPort(), //
+ "IdentityFile " + privateKey2.getAbsolutePath(), //
+ "", //
+ "Host proxy2", //
+ "Hostname localhost", //
+ "User foo", //
+ "ProxyJump " + TEST_USER + "X@proxy", //
+ "IdentityFile " + privateKey1.getAbsolutePath()));
+ assertTrue(e.getMessage().contains("proxy"));
+ } finally {
+ proxy1.stop();
+ proxy2.stop();
+ }
+ }
}
}
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index a9f1f1ceb7..96b40ad15e 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -45,6 +45,7 @@ Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)",
org.apache.sshd.client.future;version="[2.4.0,2.5.0)",
org.apache.sshd.client.keyverifier;version="[2.4.0,2.5.0)",
org.apache.sshd.client.session;version="[2.4.0,2.5.0)",
+ org.apache.sshd.client.session.forward;version="[2.4.0,2.5.0)",
org.apache.sshd.client.subsystem.sftp;version="[2.4.0,2.5.0)",
org.apache.sshd.common;version="[2.4.0,2.5.0)",
org.apache.sshd.common.auth;version="[2.4.0,2.5.0)",
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 4f85ebe100..f810fd40e4 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,10 +1,14 @@
-authenticationCanceled=Authentication canceled: no password
+authenticationCanceled=SSH authentication canceled: no password given
+authenticationOnClosedSession=Authentication canceled: session is already closing or closed
closeListenerFailed=Ssh session close listener failed
configInvalidPath=Invalid path in ssh config key {0}: {1}
configInvalidPattern=Invalid pattern in ssh config key {0}: {1}
configInvalidPositive=Ssh config entry {0} must be a strictly positive number but is ''{1}''
+configInvalidProxyJump=Ssh config, host ''{0}'': Cannot parse ProxyJump ''{1}''
configNoKnownHostKeyAlgorithms=No implementations for any of the algorithms ''{0}'' given in HostKeyAlgorithms in the ssh config; using the default.
configNoRemainingHostKeyAlgorithms=Ssh config removed all host key algorithms: HostKeyAlgorithms ''{0}''
+configProxyJumpNotSsh=Non-ssh URI in ProxyJump ssh config
+configProxyJumpWithPath=ProxyJump ssh config: jump host specification must not have a path
ftpCloseFailed=Closing the SFTP channel failed
gssapiFailure=GSS-API error for mechanism OID {0}
gssapiInitFailure=GSS-API initialization failure for mechanism {0}
@@ -45,12 +49,14 @@ knownHostsUnknownKeyPrompt=Accept and store this key, and continue connecting?
knownHostsUnknownKeyType=Cannot read server key from known hosts file {0}; line {1}
knownHostsUserAskCreationMsg=File {0} does not exist.
knownHostsUserAskCreationPrompt=Create file {0} ?
+loginDenied=Cannot log in at {0}:{1}
passwordPrompt=Password
proxyCannotAuthenticate=Cannot authenticate to proxy {0}
proxyHttpFailure=HTTP Proxy connection to {0} failed with code {1}: {2}
proxyHttpInvalidUserName=HTTP proxy connection {0} with invalid user name; must not contain colons: {1}
proxyHttpUnexpectedReply=Unexpected HTTP proxy response from {0}: {1}
proxyHttpUnspecifiedFailureReason=unspecified reason
+proxyJumpAbort=ProxyJump chain too long at {0}
proxyPasswordPrompt=Proxy password
proxySocksAuthenticationFailed=Authentication to SOCKS5 proxy {0} failed
proxySocksFailureForbidden=SOCKS5 proxy {0}: connection to {1} not allowed by ruleset
@@ -75,7 +81,9 @@ serverIdNotReceived=No server identification received within {0} bytes
serverIdTooLong=Server identification is longer than 255 characters (including line ending): {0}
serverIdWithNul=Server identification contains a NUL character: {0}
sessionCloseFailed=Closing the session failed
+sessionWithoutUsername=SSH session created without user name; cannot authenticate
sshClosingDown=Apache MINA sshd session factory is closing down; cannot create new ssh sessions on this factory
sshCommandTimeout={0} timed out after {1} seconds while opening the channel
sshProcessStillRunning={0} is not yet completed, cannot get exit code
+sshProxySessionCloseFailed=Error while closing proxy session {0}
unknownProxyProtocol=Ignoring unknown proxy protocol {0} \ No newline at end of file
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationCanceledException.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationCanceledException.java
new file mode 100644
index 0000000000..aa4623571d
--- /dev/null
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/AuthenticationCanceledException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020, 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.concurrent.CancellationException;
+
+/**
+ * An exception to report that the user canceled the SSH authentication.
+ */
+public class AuthenticationCanceledException extends CancellationException {
+
+ // If this is not a CancellationException sshd will try other authentication
+ // mechanisms.
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new {@link AuthenticationCanceledException}.
+ */
+ public AuthenticationCanceledException() {
+ super(SshdText.get().authenticationCanceled);
+ }
+}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
index 420a1d16eb..0d6f3027f2 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
@@ -18,21 +18,30 @@ import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.ClientUserAuthService;
+import org.apache.sshd.common.AttributeRepository;
import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.PropertyResolver;
import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.io.IoWriteFuture;
+import org.apache.sshd.common.kex.KexState;
import org.apache.sshd.common.util.Readable;
import org.apache.sshd.common.util.buffer.Buffer;
import org.eclipse.jgit.errors.InvalidPatternException;
@@ -68,6 +77,17 @@ public class JGitClientSession extends ClientSessionImpl {
private volatile StatefulProxyConnector proxyHandler;
/**
+ * Work-around for bug 565394 / SSHD-1050; remove when using sshd 2.6.0.
+ */
+ private volatile AuthFuture authFuture;
+
+ /** Records exceptions before there is an authFuture. */
+ private List<Throwable> earlyErrors = new ArrayList<>();
+
+ /** Guards setting an earlyError and the authFuture together. */
+ private final Object errorLock = new Object();
+
+ /**
* @param manager
* @param session
* @throws Exception
@@ -77,6 +97,125 @@ public class JGitClientSession extends ClientSessionImpl {
super(manager, session);
}
+ // BEGIN Work-around for bug 565394 / SSHD-1050
+ // Remove when using sshd 2.6.0.
+
+ @Override
+ public AuthFuture auth() throws IOException {
+ if (getUsername() == null) {
+ throw new IllegalStateException(
+ SshdText.get().sessionWithoutUsername);
+ }
+ ClientUserAuthService authService = getUserAuthService();
+ String serviceName = nextServiceName();
+ List<Throwable> errors = null;
+ AuthFuture future;
+ // Guard both getting early errors and setting authFuture
+ synchronized (errorLock) {
+ future = authService.auth(serviceName);
+ if (future == null) {
+ // Internal error; no translation.
+ throw new IllegalStateException(
+ "No auth future generated by service '" //$NON-NLS-1$
+ + serviceName + '\'');
+ }
+ errors = earlyErrors;
+ earlyErrors = null;
+ authFuture = future;
+ }
+ if (errors != null && !errors.isEmpty()) {
+ Iterator<Throwable> iter = errors.iterator();
+ Throwable first = iter.next();
+ iter.forEachRemaining(t -> {
+ if (t != first && t != null) {
+ first.addSuppressed(t);
+ }
+ });
+ // Mark the future as having had an exception; just to be on the
+ // safe side. Actually, there shouldn't be anyone waiting on this
+ // future yet.
+ future.setException(first);
+ if (log.isDebugEnabled()) {
+ log.debug("auth({}) early exception type={}: {}", //$NON-NLS-1$
+ this, first.getClass().getSimpleName(),
+ first.getMessage());
+ }
+ if (first instanceof SshException) {
+ throw new SshException(
+ ((SshException) first).getDisconnectCode(),
+ first.getMessage(), first);
+ }
+ throw new IOException(first.getMessage(), first);
+ }
+ return future;
+ }
+
+ @Override
+ protected void signalAuthFailure(AuthFuture future, Throwable t) {
+ signalAuthFailure(t);
+ }
+
+ private void signalAuthFailure(Throwable t) {
+ AuthFuture future = authFuture;
+ if (future == null) {
+ synchronized (errorLock) {
+ if (earlyErrors != null) {
+ earlyErrors.add(t);
+ }
+ future = authFuture;
+ }
+ }
+ if (future != null) {
+ future.setException(t);
+ }
+ if (log.isDebugEnabled()) {
+ boolean signalled = future != null && t == future.getException();
+ log.debug("signalAuthFailure({}) type={}, signalled={}: {}", this, //$NON-NLS-1$
+ t.getClass().getSimpleName(), Boolean.valueOf(signalled),
+ t.getMessage());
+ }
+ }
+
+ @Override
+ public void exceptionCaught(Throwable t) {
+ signalAuthFailure(t);
+ super.exceptionCaught(t);
+ }
+
+ @Override
+ protected void preClose() {
+ signalAuthFailure(
+ new SshException(SshdText.get().authenticationOnClosedSession));
+ super.preClose();
+ }
+
+ @Override
+ protected void handleDisconnect(int code, String msg, String lang,
+ Buffer buffer) throws Exception {
+ signalAuthFailure(new SshException(code, msg));
+ super.handleDisconnect(code, msg, lang, buffer);
+ }
+
+ @Override
+ protected <C extends Collection<ClientSessionEvent>> C updateCurrentSessionState(
+ C newState) {
+ if (closeFuture.isClosed()) {
+ newState.add(ClientSessionEvent.CLOSED);
+ }
+ if (isAuthenticated()) { // authFuture.isSuccess()
+ newState.add(ClientSessionEvent.AUTHED);
+ }
+ if (KexState.DONE.equals(getKexState())) {
+ AuthFuture future = authFuture;
+ if (future == null || future.isFailure()) {
+ newState.add(ClientSessionEvent.WAIT_AUTH);
+ }
+ }
+ return newState;
+ }
+
+ // END Work-around for bug 565394 / SSHD-1050
+
/**
* Retrieves the {@link HostConfigEntry} this session was created for.
*
@@ -419,4 +558,122 @@ public class JGitClientSession extends ClientSessionImpl {
return b.toString();
}
+ @Override
+ public <T> T getAttribute(AttributeKey<T> key) {
+ T value = super.getAttribute(key);
+ if (value == null) {
+ IoSession ioSession = getIoSession();
+ if (ioSession != null) {
+ Object obj = ioSession.getAttribute(AttributeRepository.class);
+ if (obj instanceof AttributeRepository) {
+ AttributeRepository sessionAttributes = (AttributeRepository) obj;
+ value = sessionAttributes.resolveAttribute(key);
+ }
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public PropertyResolver getParentPropertyResolver() {
+ IoSession ioSession = getIoSession();
+ if (ioSession != null) {
+ Object obj = ioSession.getAttribute(AttributeRepository.class);
+ if (obj instanceof PropertyResolver) {
+ return (PropertyResolver) obj;
+ }
+ }
+ return super.getParentPropertyResolver();
+ }
+
+ /**
+ * An {@link AttributeRepository} that chains together two other attribute
+ * sources in a hierarchy.
+ */
+ public static class ChainingAttributes implements AttributeRepository {
+
+ private final AttributeRepository delegate;
+
+ private final AttributeRepository parent;
+
+ /**
+ * Create a new {@link ChainingAttributes} attribute source.
+ *
+ * @param self
+ * to search for attributes first
+ * @param parent
+ * to search for attributes if not found in {@code self}
+ */
+ public ChainingAttributes(AttributeRepository self,
+ AttributeRepository parent) {
+ this.delegate = self;
+ this.parent = parent;
+ }
+
+ @Override
+ public int getAttributesCount() {
+ return delegate.getAttributesCount();
+ }
+
+ @Override
+ public <T> T getAttribute(AttributeKey<T> key) {
+ return delegate.getAttribute(Objects.requireNonNull(key));
+ }
+
+ @Override
+ public Collection<AttributeKey<?>> attributeKeys() {
+ return delegate.attributeKeys();
+ }
+
+ @Override
+ public <T> T resolveAttribute(AttributeKey<T> key) {
+ T value = getAttribute(Objects.requireNonNull(key));
+ if (value == null) {
+ return parent.getAttribute(key);
+ }
+ return value;
+ }
+ }
+
+ /**
+ * A {@link ChainingAttributes} repository that doubles as a
+ * {@link PropertyResolver}. The property map can be set via the attribute
+ * key {@link SessionAttributes#PROPERTIES}.
+ */
+ public static class SessionAttributes extends ChainingAttributes
+ implements PropertyResolver {
+
+ /** Key for storing a map of properties in the attributes. */
+ public static final AttributeKey<Map<String, Object>> PROPERTIES = new AttributeKey<>();
+
+ private final PropertyResolver parentProperties;
+
+ /**
+ * Creates a new {@link SessionAttributes} attribute and property
+ * source.
+ *
+ * @param self
+ * to search for attributes first
+ * @param parent
+ * to search for attributes if not found in {@code self}
+ * @param parentProperties
+ * to search for properties if not found in {@code self}
+ */
+ public SessionAttributes(AttributeRepository self,
+ AttributeRepository parent, PropertyResolver parentProperties) {
+ super(self, parent);
+ this.parentProperties = parentProperties;
+ }
+
+ @Override
+ public PropertyResolver getParentPropertyResolver() {
+ return parentProperties;
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ Map<String, Object> props = getAttribute(PROPERTIES);
+ return props == null ? Collections.emptyMap() : props;
+ }
+ }
}
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 0a7082cefe..4abd6e901a 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
@@ -9,8 +9,6 @@
*/
package org.eclipse.jgit.internal.transport.sshd;
-import java.util.concurrent.CancellationException;
-
import org.apache.sshd.client.ClientAuthenticationManager;
import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.auth.password.UserAuthPassword;
@@ -49,7 +47,7 @@ public class JGitPasswordAuthentication extends UserAuthPassword {
}
String password = getPassword(session, interaction);
if (password == null) {
- throw new CancellationException();
+ throw new AuthenticationCanceledException();
}
// sendPassword takes a buffer as first argument, but actually doesn't
// use it and creates its own buffer...
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 b8dd60fb10..beaaecaac9 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, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -23,12 +23,16 @@ import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.util.Arrays;
+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.Objects;
import java.util.stream.Collectors;
+import org.apache.sshd.client.ClientAuthenticationManager;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.future.ConnectFuture;
@@ -45,6 +49,9 @@ import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.common.session.helpers.AbstractSession;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.eclipse.jgit.internal.transport.sshd.JGitClientSession.ChainingAttributes;
+import org.eclipse.jgit.internal.transport.sshd.JGitClientSession.SessionAttributes;
import org.eclipse.jgit.internal.transport.sshd.proxy.HttpClientConnector;
import org.eclipse.jgit.internal.transport.sshd.proxy.Socks5ClientConnector;
import org.eclipse.jgit.transport.CredentialsProvider;
@@ -52,6 +59,7 @@ import org.eclipse.jgit.transport.SshConstants;
import org.eclipse.jgit.transport.sshd.KeyCache;
import org.eclipse.jgit.transport.sshd.ProxyData;
import org.eclipse.jgit.transport.sshd.ProxyDataFactory;
+import org.eclipse.jgit.util.StringUtils;
/**
* Customized {@link SshClient} for JGit. It creates specialized
@@ -75,6 +83,16 @@ public class JGitSshClient extends SshClient {
*/
public static final AttributeKey<String> PREFERRED_AUTHENTICATIONS = 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)}
+ * will not connect to the address obtained from the {@link HostConfigEntry}
+ * but to the address stored in this key (which is assumed to forward the
+ * {@code HostConfigEntry} address).
+ */
+ public static final AttributeKey<SshdSocketAddress> LOCAL_FORWARD_ADDRESS = new AttributeKey<>();
+
private KeyCache keyCache;
private CredentialsProvider credentialsProvider;
@@ -95,40 +113,72 @@ public class JGitSshClient extends SshClient {
throw new IllegalStateException("SshClient not started."); //$NON-NLS-1$
}
Objects.requireNonNull(hostConfig, "No host configuration"); //$NON-NLS-1$
- String host = ValidateUtils.checkNotNullAndNotEmpty(
+ String originalHost = ValidateUtils.checkNotNullAndNotEmpty(
hostConfig.getHostName(), "No target host"); //$NON-NLS-1$
- int port = hostConfig.getPort();
- ValidateUtils.checkTrue(port > 0, "Invalid port: %d", port); //$NON-NLS-1$
+ int originalPort = hostConfig.getPort();
+ ValidateUtils.checkTrue(originalPort > 0, "Invalid port: %d", //$NON-NLS-1$
+ originalPort);
+ InetSocketAddress originalAddress = new InetSocketAddress(originalHost,
+ originalPort);
+ InetSocketAddress targetAddress = originalAddress;
String userName = hostConfig.getUsername();
- InetSocketAddress address = new InetSocketAddress(host, port);
- ConnectFuture connectFuture = new DefaultConnectFuture(
- userName + '@' + address, null);
+ String id = userName + '@' + originalAddress;
+ AttributeRepository attributes = chain(context, this);
+ SshdSocketAddress localForward = attributes
+ .resolveAttribute(LOCAL_FORWARD_ADDRESS);
+ if (localForward != null) {
+ targetAddress = new InetSocketAddress(localForward.getHostName(),
+ localForward.getPort());
+ id += '/' + targetAddress.toString();
+ }
+ ConnectFuture connectFuture = new DefaultConnectFuture(id, null);
SshFutureListener<IoConnectFuture> listener = createConnectCompletionListener(
- connectFuture, userName, address, hostConfig);
- // sshd needs some entries from the host config already in the
- // constructor of the session. Put those as properties on this client,
- // where it will find them. We can set the host config only once the
- // session object has been created.
- copyProperty(
- hostConfig.getProperty(SshConstants.PREFERRED_AUTHENTICATIONS,
- getAttribute(PREFERRED_AUTHENTICATIONS)),
- PREFERRED_AUTHS);
- setAttribute(HOST_CONFIG_ENTRY, hostConfig);
- setAttribute(ORIGINAL_REMOTE_ADDRESS, address);
+ connectFuture, userName, originalAddress, hostConfig);
+ attributes = sessionAttributes(attributes, hostConfig, originalAddress);
// Proxy support
- ProxyData proxy = getProxyData(address);
- if (proxy != null) {
- address = configureProxy(proxy, address);
- proxy.clearPassword();
+ if (localForward == null) {
+ ProxyData proxy = getProxyData(targetAddress);
+ if (proxy != null) {
+ targetAddress = configureProxy(proxy, targetAddress);
+ proxy.clearPassword();
+ }
}
- connector.connect(address, this, localAddress).addListener(listener);
+ connector.connect(targetAddress, attributes, localAddress)
+ .addListener(listener);
return connectFuture;
}
- private void copyProperty(String value, String key) {
- if (value != null && !value.isEmpty()) {
- getProperties().put(key, value);
+ private AttributeRepository chain(AttributeRepository self,
+ AttributeRepository parent) {
+ if (self == null) {
+ return Objects.requireNonNull(parent);
}
+ if (parent == null || parent == self) {
+ return self;
+ }
+ return new ChainingAttributes(self, parent);
+ }
+
+ private AttributeRepository sessionAttributes(AttributeRepository parent,
+ HostConfigEntry hostConfig, InetSocketAddress originalAddress) {
+ // sshd needs some entries from the host config already in the
+ // constructor of the session. Put those into a dedicated
+ // AttributeRepository for the new session where it will find them.
+ // We can set the host config only once the session object has been
+ // created.
+ Map<AttributeKey<?>, Object> data = new HashMap<>();
+ data.put(HOST_CONFIG_ENTRY, hostConfig);
+ data.put(ORIGINAL_REMOTE_ADDRESS, originalAddress);
+ String preferredAuths = hostConfig.getProperty(
+ SshConstants.PREFERRED_AUTHENTICATIONS,
+ resolveAttribute(PREFERRED_AUTHENTICATIONS));
+ if (!StringUtils.isEmptyOrNull(preferredAuths)) {
+ data.put(SessionAttributes.PROPERTIES,
+ Collections.singletonMap(PREFERRED_AUTHS, preferredAuths));
+ }
+ return new SessionAttributes(
+ AttributeRepository.ofAttributesMap(data),
+ parent, this);
}
private ProxyData getProxyData(InetSocketAddress remoteAddress) {
@@ -219,11 +269,6 @@ public class JGitSshClient extends SshClient {
int numberOfPasswordPrompts = getNumberOfPasswordPrompts(hostConfig);
session.getProperties().put(PASSWORD_PROMPTS,
Integer.valueOf(numberOfPasswordPrompts));
- FilePasswordProvider passwordProvider = getFilePasswordProvider();
- if (passwordProvider instanceof RepeatingFilePasswordProvider) {
- ((RepeatingFilePasswordProvider) passwordProvider)
- .setAttempts(numberOfPasswordPrompts);
- }
List<Path> identities = hostConfig.getIdentities().stream()
.map(s -> {
try {
@@ -237,6 +282,7 @@ public class JGitSshClient extends SshClient {
.collect(Collectors.toList());
CachingKeyPairProvider ourConfiguredKeysProvider = new CachingKeyPairProvider(
identities, keyCache);
+ FilePasswordProvider passwordProvider = getFilePasswordProvider();
ourConfiguredKeysProvider.setPasswordFinder(passwordProvider);
if (hostConfig.isIdentitiesOnly()) {
session.setKeyIdentityProvider(ourConfiguredKeysProvider);
@@ -265,9 +311,7 @@ public class JGitSshClient extends SshClient {
log.warn(format(SshdText.get().configInvalidPositive,
SshConstants.NUMBER_OF_PASSWORD_PROMPTS, prompts));
}
- // Default for NumberOfPasswordPrompts according to
- // https://man.openbsd.org/ssh_config
- return 3;
+ return ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS;
}
/**
@@ -408,6 +452,5 @@ public class JGitSshClient extends SshClient {
};
}
-
}
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
index 5b48a8cf99..078e411f29 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/PasswordProviderWrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -16,8 +16,12 @@ import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import org.apache.sshd.client.ClientAuthenticationManager;
+import org.apache.sshd.common.AttributeRepository.AttributeKey;
import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.session.SessionContext;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.transport.CredentialsProvider;
@@ -25,39 +29,61 @@ import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.sshd.KeyPasswordProvider;
/**
- * A bridge from sshd's {@link RepeatingFilePasswordProvider} to our
+ * A bridge from sshd's {@link FilePasswordProvider} to our per-session
* {@link KeyPasswordProvider} API.
*/
-public class PasswordProviderWrapper implements RepeatingFilePasswordProvider {
+public class PasswordProviderWrapper implements FilePasswordProvider {
- private final KeyPasswordProvider delegate;
+ private static final AttributeKey<PerSessionState> STATE = new AttributeKey<>();
- private Map<String, AtomicInteger> counts = new ConcurrentHashMap<>();
+ private static class PerSessionState {
+
+ Map<String, AtomicInteger> counts = new ConcurrentHashMap<>();
+
+ KeyPasswordProvider delegate;
- /**
- * @param delegate
- */
- public PasswordProviderWrapper(@NonNull KeyPasswordProvider delegate) {
- this.delegate = delegate;
}
- @Override
- public void setAttempts(int numberOfPasswordPrompts) {
- delegate.setAttempts(numberOfPasswordPrompts);
+ private final Supplier<KeyPasswordProvider> factory;
+
+ /**
+ * Creates a new {@link PasswordProviderWrapper}.
+ *
+ * @param factory
+ * to use to create per-session {@link KeyPasswordProvider}s
+ */
+ public PasswordProviderWrapper(
+ @NonNull Supplier<KeyPasswordProvider> factory) {
+ this.factory = factory;
}
- @Override
- public int getAttempts() {
- return delegate.getAttempts();
+ private PerSessionState getState(SessionContext context) {
+ PerSessionState state = context.getAttribute(STATE);
+ if (state == null) {
+ state = new PerSessionState();
+ state.delegate = factory.get();
+ Integer maxNumberOfAttempts = context
+ .getInteger(ClientAuthenticationManager.PASSWORD_PROMPTS);
+ if (maxNumberOfAttempts != null
+ && maxNumberOfAttempts.intValue() > 0) {
+ state.delegate.setAttempts(maxNumberOfAttempts.intValue());
+ } else {
+ state.delegate.setAttempts(
+ ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS);
+ }
+ context.setAttribute(STATE, state);
+ }
+ return state;
}
@Override
public String getPassword(SessionContext session, NamedResource resource,
int attemptIndex) throws IOException {
String key = resource.getName();
- int attempt = counts
+ PerSessionState state = getState(session);
+ int attempt = state.counts
.computeIfAbsent(key, k -> new AtomicInteger()).get();
- char[] passphrase = delegate.getPassphrase(toUri(key), attempt);
+ char[] passphrase = state.delegate.getPassphrase(toUri(key), attempt);
if (passphrase == null) {
return null;
}
@@ -74,18 +100,19 @@ public class PasswordProviderWrapper implements RepeatingFilePasswordProvider {
String password, Exception err)
throws IOException, GeneralSecurityException {
String key = resource.getName();
- AtomicInteger count = counts.get(key);
+ PerSessionState state = getState(session);
+ AtomicInteger count = state.counts.get(key);
int numberOfAttempts = count == null ? 0 : count.incrementAndGet();
ResourceDecodeResult result = null;
try {
- if (delegate.keyLoaded(toUri(key), numberOfAttempts, err)) {
+ if (state.delegate.keyLoaded(toUri(key), numberOfAttempts, err)) {
result = ResourceDecodeResult.RETRY;
} else {
result = ResourceDecodeResult.TERMINATE;
}
} finally {
if (result != ResourceDecodeResult.RETRY) {
- counts.remove(key);
+ state.counts.remove(key);
}
}
return result;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
deleted file mode 100644
index 86f0fe7b60..0000000000
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/RepeatingFilePasswordProvider.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018, 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 org.apache.sshd.common.config.keys.FilePasswordProvider;
-
-/**
- * A {@link FilePasswordProvider} augmented to support repeatedly asking for
- * passwords.
- *
- */
-public interface RepeatingFilePasswordProvider extends FilePasswordProvider {
-
- /**
- * Define the maximum number of attempts to get a password that should be
- * attempted for one identity resource through this provider.
- *
- * @param numberOfPasswordPrompts
- * number of times to ask for a password;
- * {@link IllegalArgumentException} may be thrown if <= 0
- */
- void setAttempts(int numberOfPasswordPrompts);
-
- /**
- * Gets the maximum number of attempts to get a password that should be
- * attempted for one identity resource through this provider.
- *
- * @return the maximum number of attempts to try, always >= 1.
- */
- default int getAttempts() {
- return 1;
- }
-
-}
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 f67170e407..13bb3ebe75 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
@@ -19,12 +19,16 @@ public final class SshdText extends TranslationBundle {
// @formatter:off
/***/ public String authenticationCanceled;
+ /***/ public String authenticationOnClosedSession;
/***/ public String closeListenerFailed;
/***/ public String configInvalidPath;
/***/ public String configInvalidPattern;
/***/ public String configInvalidPositive;
+ /***/ public String configInvalidProxyJump;
/***/ public String configNoKnownHostKeyAlgorithms;
/***/ public String configNoRemainingHostKeyAlgorithms;
+ /***/ public String configProxyJumpNotSsh;
+ /***/ public String configProxyJumpWithPath;
/***/ public String ftpCloseFailed;
/***/ public String gssapiFailure;
/***/ public String gssapiInitFailure;
@@ -57,12 +61,14 @@ public final class SshdText extends TranslationBundle {
/***/ public String knownHostsUnknownKeyType;
/***/ public String knownHostsUserAskCreationMsg;
/***/ public String knownHostsUserAskCreationPrompt;
+ /***/ public String loginDenied;
/***/ public String passwordPrompt;
/***/ public String proxyCannotAuthenticate;
/***/ public String proxyHttpFailure;
/***/ public String proxyHttpInvalidUserName;
/***/ public String proxyHttpUnexpectedReply;
/***/ public String proxyHttpUnspecifiedFailureReason;
+ /***/ public String proxyJumpAbort;
/***/ public String proxyPasswordPrompt;
/***/ public String proxySocksAuthenticationFailed;
/***/ public String proxySocksFailureForbidden;
@@ -87,9 +93,11 @@ public final class SshdText extends TranslationBundle {
/***/ public String serverIdTooLong;
/***/ public String serverIdWithNul;
/***/ public String sessionCloseFailed;
+ /***/ public String sessionWithoutUsername;
/***/ public String sshClosingDown;
/***/ public String sshCommandTimeout;
/***/ public String sshProcessStillRunning;
+ /***/ public String sshProxySessionCloseFailed;
/***/ public String unknownProxyProtocol;
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java
index d5b80374cb..0500a63428 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java
@@ -13,6 +13,8 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import org.eclipse.jgit.util.HttpSupport;
+
/**
* A basic parser for HTTP response headers. Handles status lines and
* authentication headers (WWW-Authenticate, Proxy-Authenticate).
@@ -135,7 +137,7 @@ public final class HttpParser {
int length = header.length();
for (int i = 0; i < length;) {
int start = skipWhiteSpace(header, i);
- int end = scanToken(header, start);
+ int end = HttpSupport.scanToken(header, start);
if (end <= start) {
break;
}
@@ -156,7 +158,7 @@ public final class HttpParser {
// optional legacy whitespace around the equals sign), where the
// value can be either a token or a quoted string.
start = skipWhiteSpace(header, start);
- int end = scanToken(header, start);
+ int end = HttpSupport.scanToken(header, start);
if (end == start) {
// Nothing found. Either at end or on a comma.
if (start < header.length() && header.charAt(start) == ',') {
@@ -222,7 +224,7 @@ public final class HttpParser {
challenge.addArgument(header.substring(start, end), value);
start = nextEnd[0];
} else {
- int nextEnd = scanToken(header, nextStart);
+ int nextEnd = HttpSupport.scanToken(header, nextStart);
challenge.addArgument(header.substring(start, end),
header.substring(nextStart, nextEnd));
start = nextEnd;
@@ -244,49 +246,6 @@ public final class HttpParser {
return i;
}
- private static int scanToken(String header, int from) {
- int length = header.length();
- int i = from;
- while (i < length) {
- char c = header.charAt(i);
- switch (c) {
- case '!':
- case '#':
- case '$':
- case '%':
- case '&':
- case '\'':
- case '*':
- case '+':
- case '-':
- case '.':
- case '^':
- case '_':
- case '`':
- case '|':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- i++;
- break;
- default:
- if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') {
- i++;
- break;
- }
- return i;
- }
- }
- return i;
- }
-
private static String scanQuotedString(String header, int from, int[] to) {
StringBuilder result = new StringBuilder();
int length = header.length();
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java
index 004d3f8361..dd6894b662 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/IdentityPasswordProvider.java
@@ -19,13 +19,14 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CancellationException;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.internal.transport.sshd.AuthenticationCanceledException;
import org.eclipse.jgit.internal.transport.sshd.SshdText;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.StringUtils;
/**
* A {@link KeyPasswordProvider} based on a {@link CredentialsProvider}.
@@ -155,35 +156,84 @@ public class IdentityPasswordProvider implements KeyPasswordProvider {
state.incCount();
String message = state.count == 1 ? SshdText.get().keyEncryptedMsg
: SshdText.get().keyEncryptedRetry;
- char[] pass = getPassword(uri, message);
+ char[] pass = getPassword(uri, format(message, uri));
state.setPassword(pass);
return pass;
}
- private char[] getPassword(URIish uri, String message) {
+ /**
+ * Retrieves the JGit {@link CredentialsProvider} to use for user
+ * interaction.
+ *
+ * @return the {@link CredentialsProvider} or {@code null} if none
+ * configured
+ * @since 5.10
+ */
+ protected CredentialsProvider getCredentialsProvider() {
+ return provider;
+ }
+
+ /**
+ * Obtains the passphrase/password for an encrypted private key via the
+ * {@link #getCredentialsProvider() configured CredentialsProvider}.
+ *
+ * @param uri
+ * identifying the resource to obtain a password for
+ * @param message
+ * optional message text to display; may be {@code null} or empty
+ * if none
+ * @return the password entered, or {@code null} if no
+ * {@link CredentialsProvider} is configured or none was entered
+ * @throws java.util.concurrent.CancellationException
+ * if the user canceled the operation
+ * @since 5.10
+ */
+ protected char[] getPassword(URIish uri, String message) {
if (provider == null) {
return null;
}
- List<CredentialItem> items = new ArrayList<>(2);
- items.add(new CredentialItem.InformationalMessage(
- format(message, uri)));
+ boolean haveMessage = !StringUtils.isEmptyOrNull(message);
+ List<CredentialItem> items = new ArrayList<>(haveMessage ? 2 : 1);
+ if (haveMessage) {
+ items.add(new CredentialItem.InformationalMessage(message));
+ }
CredentialItem.Password password = new CredentialItem.Password(
SshdText.get().keyEncryptedPrompt);
items.add(password);
try {
- provider.get(uri, items);
+ boolean completed = provider.get(uri, items);
char[] pass = password.getValue();
- if (pass == null) {
- throw new CancellationException(
- SshdText.get().authenticationCanceled);
+ if (!completed) {
+ cancelAuthentication();
+ return null;
}
- return pass.clone();
+ return pass == null ? null : pass.clone();
} finally {
password.clear();
}
}
/**
+ * Cancels the authentication process. Called by
+ * {@link #getPassword(URIish, String)} when the user interaction has been
+ * canceled. If this throws a
+ * {@link java.util.concurrent.CancellationException}, the authentication
+ * process is aborted; otherwise it may continue with the next configured
+ * authentication mechanism, if any.
+ * <p>
+ * This default implementation always throws a
+ * {@link java.util.concurrent.CancellationException}.
+ * </p>
+ *
+ * @throws java.util.concurrent.CancellationException
+ * always
+ * @since 5.10
+ */
+ protected void cancelAuthentication() {
+ throw new AuthenticationCanceledException();
+ }
+
+ /**
* Invoked to inform the password provider about the decoding result.
*
* @param uri
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 0c1533c614..0fb0610b99 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, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -10,37 +10,53 @@
package org.eclipse.jgit.transport.sshd;
import static java.text.MessageFormat.format;
+import static org.apache.sshd.common.SshConstants.SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InterruptedIOException;
import java.io.OutputStream;
+import java.net.URISyntaxException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.EnumSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
+import java.util.regex.Pattern;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ClientChannelEvent;
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
+import org.apache.sshd.client.future.ConnectFuture;
import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.session.forward.PortForwardingTracker;
import org.apache.sshd.client.subsystem.sftp.SftpClient;
import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
import org.apache.sshd.client.subsystem.sftp.SftpClient.CopyMode;
import org.apache.sshd.client.subsystem.sftp.SftpClientFactory;
-import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.common.AttributeRepository;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.subsystem.sftp.SftpException;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
import org.eclipse.jgit.internal.transport.sshd.SshdText;
import org.eclipse.jgit.transport.FtpChannel;
import org.eclipse.jgit.transport.RemoteSession;
+import org.eclipse.jgit.transport.SshConstants;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,6 +70,11 @@ public class SshdSession implements RemoteSession {
private static final Logger LOG = LoggerFactory
.getLogger(SshdSession.class);
+ private static final Pattern SHORT_SSH_FORMAT = Pattern
+ .compile("[-\\w.]+(?:@[-\\w.]+)?(?::\\d+)?"); //$NON-NLS-1$
+
+ private static final int MAX_DEPTH = 10;
+
private final CopyOnWriteArrayList<SessionCloseListener> listeners = new CopyOnWriteArrayList<>();
private final URIish uri;
@@ -72,32 +93,169 @@ public class SshdSession implements RemoteSession {
client.start();
}
try {
- String username = uri.getUser();
- String host = uri.getHost();
- int port = uri.getPort();
- long t = timeout.toMillis();
- if (t <= 0) {
- session = client.connect(username, host, port).verify()
- .getSession();
- } else {
- session = client.connect(username, host, port)
- .verify(timeout.toMillis()).getSession();
- }
- session.addSessionListener(new SessionListener() {
+ session = connect(uri, Collections.emptyList(),
+ future -> notifyCloseListeners(), timeout, MAX_DEPTH);
+ } catch (IOException e) {
+ disconnect(e);
+ throw e;
+ }
+ }
- @Override
- public void sessionClosed(Session s) {
- notifyCloseListeners();
+ private ClientSession connect(URIish target, List<URIish> jumps,
+ SshFutureListener<CloseFuture> listener, Duration timeout,
+ int depth) throws IOException {
+ if (--depth < 0) {
+ throw new IOException(
+ format(SshdText.get().proxyJumpAbort, target));
+ }
+ HostConfigEntry hostConfig = getHostConfig(target.getUser(),
+ target.getHost(), target.getPort());
+ String host = hostConfig.getHostName();
+ int port = hostConfig.getPort();
+ List<URIish> hops = determineHops(jumps, hostConfig, target.getHost());
+ ClientSession resultSession = null;
+ ClientSession proxySession = null;
+ PortForwardingTracker portForward = null;
+ try {
+ if (!hops.isEmpty()) {
+ URIish hop = hops.remove(0);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Connecting to jump host {}", hop); //$NON-NLS-1$
}
- });
+ proxySession = connect(hop, hops, null, timeout, depth);
+ }
+ AttributeRepository context = null;
+ if (proxySession != null) {
+ SshdSocketAddress remoteAddress = new SshdSocketAddress(host,
+ port);
+ portForward = proxySession.createLocalPortForwardingTracker(
+ SshdSocketAddress.LOCALHOST_ADDRESS, remoteAddress);
+ // We must connect to the locally bound address, not the one
+ // from the host config.
+ context = AttributeRepository.ofKeyValuePair(
+ JGitSshClient.LOCAL_FORWARD_ADDRESS,
+ portForward.getBoundAddress());
+ }
+ resultSession = connect(hostConfig, context, timeout);
+ if (proxySession != null) {
+ final PortForwardingTracker tracker = portForward;
+ final ClientSession pSession = proxySession;
+ resultSession.addCloseFutureListener(future -> {
+ IoUtils.closeQuietly(tracker);
+ String sessionName = pSession.toString();
+ try {
+ pSession.close();
+ } catch (IOException e) {
+ LOG.error(format(
+ SshdText.get().sshProxySessionCloseFailed,
+ sessionName), e);
+ }
+ });
+ portForward = null;
+ proxySession = null;
+ }
+ if (listener != null) {
+ resultSession.addCloseFutureListener(listener);
+ }
// Authentication timeout is by default 2 minutes.
- session.auth().verify(session.getAuthTimeout());
+ resultSession.auth().verify(resultSession.getAuthTimeout());
+ return resultSession;
} catch (IOException e) {
- disconnect(e);
+ close(portForward, e);
+ close(proxySession, e);
+ 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.
+ throw new TransportException(target,
+ format(SshdText.get().loginDenied, host,
+ Integer.toString(port)),
+ e);
+ }
throw e;
}
}
+ private ClientSession connect(HostConfigEntry config,
+ AttributeRepository context, Duration timeout)
+ throws IOException {
+ ConnectFuture connected = client.connect(config, context, null);
+ long timeoutMillis = timeout.toMillis();
+ if (timeoutMillis <= 0) {
+ connected = connected.verify();
+ } else {
+ connected = connected.verify(timeoutMillis);
+ }
+ return connected.getSession();
+ }
+
+ private void close(Closeable toClose, Throwable error) {
+ if (toClose != null) {
+ try {
+ toClose.close();
+ } catch (IOException e) {
+ error.addSuppressed(e);
+ }
+ }
+ }
+
+ private HostConfigEntry getHostConfig(String username, String host,
+ int port) throws IOException {
+ HostConfigEntry entry = client.getHostConfigEntryResolver()
+ .resolveEffectiveHost(host, port, null, username, null);
+ if (entry == null) {
+ if (SshdSocketAddress.isIPv6Address(host)) {
+ return new HostConfigEntry("", host, port, username); //$NON-NLS-1$
+ }
+ return new HostConfigEntry(host, host, port, username);
+ }
+ return entry;
+ }
+
+ private List<URIish> determineHops(List<URIish> currentHops,
+ HostConfigEntry hostConfig, String host) throws IOException {
+ if (currentHops.isEmpty()) {
+ String jumpHosts = hostConfig.getProperty(SshConstants.PROXY_JUMP);
+ if (!StringUtils.isEmptyOrNull(jumpHosts)) {
+ try {
+ return parseProxyJump(jumpHosts);
+ } catch (URISyntaxException e) {
+ throw new IOException(
+ format(SshdText.get().configInvalidProxyJump, host,
+ jumpHosts),
+ e);
+ }
+ }
+ }
+ return currentHops;
+ }
+
+ private List<URIish> parseProxyJump(String proxyJump)
+ throws URISyntaxException {
+ String[] hops = proxyJump.split(","); //$NON-NLS-1$
+ List<URIish> result = new LinkedList<>();
+ for (String hop : hops) {
+ // There shouldn't be any whitespace, but let's be lenient
+ hop = hop.trim();
+ if (SHORT_SSH_FORMAT.matcher(hop).matches()) {
+ // URIish doesn't understand the short SSH format
+ // user@host:port, only user@host:path
+ hop = SshConstants.SSH_SCHEME + "://" + hop; //$NON-NLS-1$
+ }
+ URIish to = new URIish(hop);
+ if (!SshConstants.SSH_SCHEME.equalsIgnoreCase(to.getScheme())) {
+ throw new URISyntaxException(hop,
+ SshdText.get().configProxyJumpNotSsh);
+ } else if (!StringUtils.isEmptyOrNull(to.getPath())) {
+ throw new URISyntaxException(hop,
+ SshdText.get().configProxyJumpWithPath);
+ }
+ result.add(to);
+ }
+ return result;
+ }
+
/**
* Adds a {@link SessionCloseListener} to this session. Has no effect if the
* given {@code listener} is already registered with this session.
@@ -134,28 +292,23 @@ public class SshdSession implements RemoteSession {
public Process exec(String commandName, int timeout) throws IOException {
@SuppressWarnings("resource")
ChannelExec exec = session.createExecChannel(commandName);
- long timeoutMillis = TimeUnit.SECONDS.toMillis(timeout);
- try {
- if (timeout <= 0) {
+ if (timeout <= 0) {
+ try {
exec.open().verify();
- } else {
- long start = System.nanoTime();
- exec.open().verify(timeoutMillis);
- timeoutMillis -= TimeUnit.NANOSECONDS
- .toMillis(System.nanoTime() - start);
+ } catch (IOException | RuntimeException e) {
+ exec.close(true);
+ throw e;
+ }
+ } else {
+ try {
+ exec.open().verify(TimeUnit.SECONDS.toMillis(timeout));
+ } catch (IOException | RuntimeException e) {
+ exec.close(true);
+ throw new IOException(format(SshdText.get().sshCommandTimeout,
+ commandName, Integer.valueOf(timeout)), e);
}
- } catch (IOException | RuntimeException e) {
- exec.close(true);
- throw e;
- }
- if (timeout > 0 && timeoutMillis <= 0) {
- // We have used up the whole timeout for opening the channel
- exec.close(true);
- throw new InterruptedIOException(
- format(SshdText.get().sshCommandTimeout, commandName,
- Integer.valueOf(timeout)));
}
- return new SshdExecProcess(exec, commandName, timeoutMillis);
+ return new SshdExecProcess(exec, commandName);
}
/**
@@ -195,14 +348,10 @@ public class SshdSession implements RemoteSession {
private final ChannelExec channel;
- private final long timeoutMillis;
-
private final String commandName;
- public SshdExecProcess(ChannelExec channel, String commandName,
- long timeoutMillis) {
+ public SshdExecProcess(ChannelExec channel, String commandName) {
this.channel = channel;
- this.timeoutMillis = timeoutMillis > 0 ? timeoutMillis : -1L;
this.commandName = commandName;
}
@@ -223,7 +372,7 @@ public class SshdSession implements RemoteSession {
@Override
public int waitFor() throws InterruptedException {
- if (waitFor(timeoutMillis, TimeUnit.MILLISECONDS)) {
+ if (waitFor(-1L, TimeUnit.MILLISECONDS)) {
return exitValue();
}
return -1;
@@ -252,7 +401,7 @@ public class SshdSession implements RemoteSession {
@Override
public void destroy() {
if (channel.isOpen()) {
- channel.close(true);
+ channel.close(false);
}
}
}
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 bb4e49be8e..df0e1d28a4 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, 2019 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.sshd.client.ClientBuilder;
@@ -33,6 +34,7 @@ import org.apache.sshd.client.auth.UserAuthFactory;
import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
+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;
@@ -40,6 +42,7 @@ import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
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;
@@ -194,12 +197,11 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable {
home, sshDir);
KeyIdentityProvider defaultKeysProvider = toKeyIdentityProvider(
getDefaultKeys(sshDir));
- KeyPasswordProvider passphrases = createKeyPasswordProvider(
- credentialsProvider);
SshClient client = ClientBuilder.builder()
.factory(JGitSshClient::new)
- .filePasswordProvider(
- createFilePasswordProvider(passphrases))
+ .filePasswordProvider(createFilePasswordProvider(
+ () -> createKeyPasswordProvider(
+ credentialsProvider)))
.hostConfigEntryResolver(configFile)
.serverKeyVerifier(new JGitServerKeyVerifier(
getServerKeyDatabase(home, sshDir)))
@@ -230,7 +232,16 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable {
return session;
} catch (Exception e) {
unregister(session);
- throw new TransportException(uri, e.getMessage(), e);
+ 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);
}
}
@@ -536,14 +547,14 @@ public class SshdSessionFactory extends SshSessionFactory implements Closeable {
/**
* Creates a {@link FilePasswordProvider} for a new session.
*
- * @param provider
- * the {@link KeyPasswordProvider} to delegate to
+ * @param providerFactory
+ * providing the {@link KeyPasswordProvider} to delegate to
* @return a new {@link FilePasswordProvider}
*/
@NonNull
private FilePasswordProvider createFilePasswordProvider(
- KeyPasswordProvider provider) {
- return new PasswordProviderWrapper(provider);
+ Supplier<KeyPasswordProvider> providerFactory) {
+ return new PasswordProviderWrapper(providerFactory);
}
/**
diff --git a/org.eclipse.jgit.ssh.jsch/pom.xml b/org.eclipse.jgit.ssh.jsch/pom.xml
index 2b0f1eec32..95a20b50ab 100644
--- a/org.eclipse.jgit.ssh.jsch/pom.xml
+++ b/org.eclipse.jgit.ssh.jsch/pom.xml
@@ -123,7 +123,6 @@
</configuration>
</plugin>
- <!-- No previous version to compare to
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
@@ -165,13 +164,11 @@
</execution>
</executions>
</plugin>
- -->
</plugins>
</build>
<reporting>
<plugins>
- <!-- No previous version to compare to
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
@@ -212,7 +209,6 @@
<skip>false</skip>
</configuration>
</plugin>
- -->
</plugins>
</reporting>
</project>
diff --git a/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/JschSession.java b/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/JschSession.java
index 300e03d798..858bdf3f7f 100644
--- a/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/JschSession.java
@@ -198,7 +198,7 @@ public class JschSession implements RemoteSession {
@Override
public int exitValue() {
if (isRunning())
- throw new IllegalStateException();
+ throw new IllegalThreadStateException();
return channel.getExitStatus();
}
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index c4c03b744f..d4cc7b00bd 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -48,6 +48,7 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.eclipse.jgit.lfs;version="[6.0.0,6.1.0)",
org.eclipse.jgit.lib;version="[6.0.0,6.1.0)",
org.eclipse.jgit.lib.internal;version="[6.0.0,6.1.0)",
+ org.eclipse.jgit.logging;version="[6.0.0,6.1.0)",
org.eclipse.jgit.merge;version="[6.0.0,6.1.0)",
org.eclipse.jgit.nls;version="[6.0.0,6.1.0)",
org.eclipse.jgit.notes;version="[6.0.0,6.1.0)",
diff --git a/org.eclipse.jgit.test/build.properties b/org.eclipse.jgit.test/build.properties
index 7dc26c0b0d..b527a74790 100644
--- a/org.eclipse.jgit.test/build.properties
+++ b/org.eclipse.jgit.test/build.properties
@@ -8,4 +8,4 @@ bin.includes = META-INF/,\
bin-tst/,\
bin/
additional.bundles = org.apache.log4j,\
- org.slf4j.impl.log4j12
+ org.slf4j.binding.log4j12
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v4 b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v4
new file mode 100644
index 0000000000..de49e56249
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v4
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idx
new file mode 100644
index 0000000000..20299154ee
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idxV2 b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idxV2
new file mode 100644
index 0000000000..28bd4a7774
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-bad-fanout-table.idxV2
Binary files differ
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
index b737bbec0e..de25870bd0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
@@ -92,7 +92,6 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
ObjectId id = git2.getRepository().resolve("tag-for-blob");
assertNotNull(id);
assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
@@ -277,8 +276,7 @@ public class CloneCommandTest extends RepositoryTestCase {
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
+ assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
assertEquals(
"refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
@@ -293,7 +291,6 @@ public class CloneCommandTest extends RepositoryTestCase {
git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
assertEquals("refs/remotes/origin/master, refs/remotes/origin/test",
allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
@@ -308,8 +305,7 @@ public class CloneCommandTest extends RepositoryTestCase {
git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
+ assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
.branchList().setListMode(ListMode.ALL).call()));
}
@@ -324,7 +320,6 @@ public class CloneCommandTest extends RepositoryTestCase {
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
}
@@ -338,7 +333,6 @@ public class CloneCommandTest extends RepositoryTestCase {
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
assertEquals(taggedCommit.name(), git2
.getRepository().getFullBranch());
@@ -355,10 +349,9 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertNull(git2.getRepository().resolve("tag-for-blob"));
assertNotNull(git2.getRepository().resolve("tag-initial"));
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
+ assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
assertEquals("refs/remotes/origin/master", allRefNames(git2
.branchList().setListMode(ListMode.REMOTE).call()));
RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
@@ -383,10 +376,9 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setBare(true);
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertNull(git2.getRepository().resolve("tag-for-blob"));
assertNotNull(git2.getRepository().resolve("tag-initial"));
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
+ assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
assertEquals("refs/heads/master", allRefNames(git2.branchList()
.setListMode(ListMode.ALL).call()));
RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
@@ -409,11 +401,10 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertTrue(git2.getRepository().isBare());
assertNotNull(git2.getRepository().resolve("tag-for-blob"));
assertNotNull(git2.getRepository().resolve("tag-initial"));
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
+ assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
assertEquals("refs/heads/master, refs/heads/test", allRefNames(
git2.branchList().setListMode(ListMode.ALL).call()));
assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar"));
@@ -436,7 +427,6 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertNull(git2.getRepository().resolve("tag-for-blob"));
assertNull(git2.getRepository().resolve("refs/heads/master"));
assertNotNull(git2.getRepository().resolve("tag-initial"));
@@ -464,8 +454,7 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
+ assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
// Expect both remote branches to exist; setCloneAllBranches(true)
// should override any setBranchesToClone().
assertNotNull(
@@ -492,8 +481,7 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
- assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
+ assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
// Expect only the test branch; allBranches was re-set to false
assertNull(git2.getRepository().resolve("refs/remotes/origin/master"));
assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
@@ -525,7 +513,6 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setURI(fileUri());
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
// clone again
command = Git.cloneRepository();
command.setDirectory(directory);
@@ -551,7 +538,6 @@ public class CloneCommandTest extends RepositoryTestCase {
clone.setURI(fileUri());
Git git2 = clone.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertEquals(Constants.MASTER, git2.getRepository().getBranch());
}
@@ -595,7 +581,6 @@ public class CloneCommandTest extends RepositoryTestCase {
clone.setURI(fileUri());
Git git2 = clone.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertEquals(Constants.MASTER, git2.getRepository().getBranch());
assertTrue(new File(git2.getRepository().getWorkTree(), path
@@ -683,7 +668,6 @@ public class CloneCommandTest extends RepositoryTestCase {
clone.setURI(git.getRepository().getDirectory().toURI().toString());
Git git2 = clone.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertEquals(Constants.MASTER, git2.getRepository().getBranch());
assertTrue(new File(git2.getRepository().getWorkTree(), path
@@ -813,7 +797,6 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setNoTags();
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertNotNull(git2.getRepository().resolve("refs/heads/test"));
assertNull(git2.getRepository().resolve("tag-initial"));
assertNull(git2.getRepository().resolve("tag-for-blob"));
@@ -833,13 +816,41 @@ public class CloneCommandTest extends RepositoryTestCase {
command.setTagOption(TagOpt.FETCH_TAGS);
Git git2 = command.call();
addRepoToClose(git2.getRepository());
- assertNotNull(git2);
assertNull(git2.getRepository().resolve("refs/heads/test"));
assertNotNull(git2.getRepository().resolve("tag-initial"));
assertNotNull(git2.getRepository().resolve("tag-for-blob"));
assertTagOption(git2.getRepository(), TagOpt.FETCH_TAGS);
}
+ @Test
+ public void testCloneWithHeadSymRefIsMasterCopy() throws IOException, GitAPIException {
+ // create a branch with the same head as master and switch to it
+ git.checkout().setStartPoint("master").setCreateBranch(true).setName("master-copy").call();
+
+ // when we clone the HEAD symref->master-copy means we start on master-copy and not master
+ File directory = createTempDirectory("testCloneRepositorySymRef_master-copy");
+ CloneCommand command = Git.cloneRepository();
+ command.setDirectory(directory);
+ command.setURI(fileUri());
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+ assertEquals("refs/heads/master-copy", git2.getRepository().getFullBranch());
+ }
+
+ @Test
+ public void testCloneWithHeadSymRefIsNonMasterCopy() throws IOException, GitAPIException {
+ // create a branch with the same head as test and switch to it
+ git.checkout().setStartPoint("test").setCreateBranch(true).setName("test-copy").call();
+
+ File directory = createTempDirectory("testCloneRepositorySymRef_test-copy");
+ CloneCommand command = Git.cloneRepository();
+ command.setDirectory(directory);
+ command.setURI(fileUri());
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+ assertEquals("refs/heads/test-copy", git2.getRepository().getFullBranch());
+ }
+
private void assertTagOption(Repository repo, TagOpt expectedTagOption)
throws URISyntaxException {
RemoteConfig remoteConfig = new RemoteConfig(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
index 7ba7c8d2be..b460e3f52e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
@@ -310,7 +310,7 @@ public class DescribeCommandTest extends RepositoryTestCase {
assertEquals(
"2 commits for describe commit increment expected since lightweight tag: c4 and c3",
"t2-2-g119892b", describe(c4)); // 2 commits: c4 and c3
- } else if (!useAnnotatedTags && !describeUseAllTags) {
+ } else if (!useAnnotatedTags) {
assertEquals("no matching commits expected", null, describe(c4));
} else {
assertEquals(
@@ -405,6 +405,46 @@ public class DescribeCommandTest extends RepositoryTestCase {
}
}
+ @Test
+ public void testDescribeUseAllRefsMaster() throws Exception {
+ final ObjectId c1 = modify("aaa");
+ tag("t1");
+
+ if (useAnnotatedTags || describeUseAllTags) {
+ assertEquals("t1", describe(c1));
+ } else {
+ assertEquals(null, describe(c1));
+ }
+ assertEquals("heads/master", describeAll(c1));
+ }
+
+ /**
+ * Branch off from master and then tag
+ *
+ * <pre>
+ * c1 -+ -> c2
+ * |
+ * +-> t1
+ * </pre>
+ * @throws Exception
+ * */
+ @Test
+ public void testDescribeUseAllRefsBranch() throws Exception {
+ final ObjectId c1 = modify("aaa");
+ modify("bbb");
+
+ branch("b", c1);
+ final ObjectId c3 = modify("ccc");
+ tag("t1");
+
+ if (!useAnnotatedTags && !describeUseAllTags) {
+ assertEquals(null, describe(c3));
+ } else {
+ assertEquals("t1", describe(c3));
+ }
+ assertEquals("heads/b", describeAll(c3));
+ }
+
private ObjectId merge(ObjectId c2) throws GitAPIException {
return git.merge().include(c2).call().getNewHead();
}
@@ -444,6 +484,11 @@ public class DescribeCommandTest extends RepositoryTestCase {
return describe(c1, false, false);
}
+ private String describeAll(ObjectId c1) throws GitAPIException, IOException {
+ return git.describe().setTarget(c1).setTags(describeUseAllTags)
+ .setLong(false).setAlways(false).setAll(true).call();
+ }
+
private String describe(ObjectId c1, String... patterns) throws Exception {
return git.describe().setTarget(c1).setTags(describeUseAllTags)
.setMatch(patterns).call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
index 1e3a39aad8..2a553ce1a2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolStreamTypeUtilTest.java
@@ -1,43 +1,11 @@
/*
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ * Copyright (C) 2015, 2020 Ivan Motsch <ivan.motsch@bsiag.com> and others
*
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
*
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.api;
@@ -90,16 +58,20 @@ public class EolStreamTypeUtilTest {
testCheckout(TEXT_LF, AUTO_LF, "\r", "\r");
testCheckout(TEXT_LF, AUTO_LF, "\n", "\n");
- testCheckout(TEXT_LF, AUTO_LF, "\r\n", "\n");
+ testCheckout(TEXT_LF, null, "\r\n", "\n");
+ testCheckout(null, AUTO_LF, "\r\n", "\r\n");
testCheckout(TEXT_LF, AUTO_LF, "\n\r", "\n\r");
- testCheckout(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n");
- testCheckout(TEXT_LF, AUTO_LF, "\r\n\r", "\n\r");
+ testCheckout(TEXT_LF, null, "\n\r\n", "\n\n");
+ testCheckout(null, AUTO_LF, "\n\r\n", "\n\r\n");
+ testCheckout(TEXT_LF, null, "\r\n\r", "\n\r");
+ testCheckout(null, AUTO_LF, "\r\n\r", "\r\n\r");
testCheckout(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n");
testCheckout(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r");
testCheckout(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r");
- testCheckout(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n");
+ testCheckout(TEXT_LF, null, "a\r\nb\r\n", "a\nb\n");
+ testCheckout(null, AUTO_LF, "a\r\nb\r\n", "a\r\nb\r\n");
}
@Test
@@ -153,45 +125,49 @@ public class EolStreamTypeUtilTest {
byte[] outputBytes = output.getBytes(UTF_8);
byte[] expectedConversionBytes = expectedConversion.getBytes(UTF_8);
- // test using output text and assuming it was declared TEXT
- b = new ByteArrayOutputStream();
- try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
- streamTypeText)) {
- out.write(outputBytes);
+ if (streamTypeText != null) {
+ // test using output text and assuming it was declared TEXT
+ b = new ByteArrayOutputStream();
+ try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
+ streamTypeText)) {
+ out.write(outputBytes);
+ }
+ assertArrayEquals(expectedConversionBytes, b.toByteArray());
}
- assertArrayEquals(expectedConversionBytes, b.toByteArray());
-
- // test using ouput text and assuming it was declared AUTO, using binary
- // detection
- b = new ByteArrayOutputStream();
- try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
- streamTypeWithBinaryCheck)) {
- out.write(outputBytes);
+ if (streamTypeWithBinaryCheck != null) {
+ // test using output text and assuming it was declared AUTO, using
+ // binary detection
+ b = new ByteArrayOutputStream();
+ try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
+ streamTypeWithBinaryCheck)) {
+ out.write(outputBytes);
+ }
+ assertArrayEquals(expectedConversionBytes, b.toByteArray());
}
- assertArrayEquals(expectedConversionBytes, b.toByteArray());
-
// now pollute output text with some binary bytes
outputBytes = extendWithBinaryData(outputBytes);
expectedConversionBytes = extendWithBinaryData(expectedConversionBytes);
- // again, test using output text and assuming it was declared TEXT
- b = new ByteArrayOutputStream();
- try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
- streamTypeText)) {
- out.write(outputBytes);
+ if (streamTypeText != null) {
+ // again, test using output text and assuming it was declared TEXT
+ b = new ByteArrayOutputStream();
+ try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
+ streamTypeText)) {
+ out.write(outputBytes);
+ }
+ assertArrayEquals(expectedConversionBytes, b.toByteArray());
}
- assertArrayEquals(expectedConversionBytes, b.toByteArray());
-
- // again, test using ouput text and assuming it was declared AUTO, using
- // binary
- // detection
- b = new ByteArrayOutputStream();
- try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
- streamTypeWithBinaryCheck)) {
- out.write(outputBytes);
+ if (streamTypeWithBinaryCheck != null) {
+ // again, test using output text and assuming it was declared AUTO,
+ // using binary detection
+ b = new ByteArrayOutputStream();
+ try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b,
+ streamTypeWithBinaryCheck)) {
+ out.write(outputBytes);
+ }
+ // expect no conversion
+ assertArrayEquals(outputBytes, b.toByteArray());
}
- // expect no conversion
- assertArrayEquals(outputBytes, b.toByteArray());
}
@Test
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 00f84e9aea..12ec2aae57 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
@@ -11,9 +11,11 @@ package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Collection;
+import java.util.Optional;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
@@ -34,7 +36,7 @@ public class LsRemoteCommandTest extends RepositoryTestCase {
git.add().addFilepattern("Test.txt").call();
git.commit().setMessage("Initial commit").call();
- // create a master branch and switch to it
+ // create a test branch and switch to it
git.branchCreate().setName("test").call();
RefUpdate rup = db.updateRef(Constants.HEAD);
rup.link("refs/heads/test");
@@ -104,6 +106,28 @@ public class LsRemoteCommandTest extends RepositoryTestCase {
assertEquals(2, refs.size());
}
+ @Test
+ public void testLsRemoteWithSymRefs() throws Exception {
+ File directory = createTempDirectory("testRepository");
+ CloneCommand command = Git.cloneRepository();
+ command.setDirectory(directory);
+ command.setURI(fileUri());
+ command.setCloneAllBranches(true);
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+
+
+ LsRemoteCommand lsRemoteCommand = git2.lsRemote();
+ Collection<Ref> refs = lsRemoteCommand.call();
+ assertNotNull(refs);
+ assertEquals(6, refs.size());
+
+ Optional<Ref> headRef = refs.stream().filter(ref -> ref.getName().equals(Constants.HEAD)).findFirst();
+ assertTrue("expected a HEAD Ref", headRef.isPresent());
+ assertTrue("expected HEAD Ref to be a Symbolic", headRef.get().isSymbolic());
+ assertEquals("refs/heads/test", headRef.get().getTarget().getName());
+ }
+
private String fileUri() {
return "file://" + git.getRepository().getWorkTree().getAbsolutePath();
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
index e0a1c1d61b..f52b715d39 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, Kevin Sawicki <kevin@github.com> and others
+ * Copyright (C) 2011, 2020 Kevin Sawicki <kevin@github.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
@@ -24,6 +24,7 @@ import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.StoredConfig;
@@ -310,6 +311,16 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {
}
@Test
+ public void testCheckoutFileWithConflict() throws Exception {
+ setupConflictingState();
+ assertEquals('[' + FILE1 + ']',
+ git.status().call().getConflicting().toString());
+ git.checkout().setStartPoint(Constants.HEAD).addPath(FILE1).call();
+ assertEquals("3", read(FILE1));
+ assertTrue(git.status().call().isClean());
+ }
+
+ @Test
public void testCheckoutOursWhenNoBase() throws Exception {
String file = "added.txt";
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
index 7e0de82d82..5311edb0eb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
@@ -160,4 +160,25 @@ public class StatusCommandTest extends RepositoryTestCase {
assertTrue("Expected no differences", status.isClean());
}
}
+
+ @Test
+ public void testFolderPrefix() throws Exception {
+ // "audio" is a prefix of "audio-new" and "audio.new".
+ try (Git git = new Git(db)) {
+ // Order here is the git order, but that doesn't really matter.
+ // They are processed by StatusCommand in this order even if written
+ // in a different order. Bug 566799 would, when having processed
+ // audio/foo, remove previously recorded untracked folders that have
+ // "audio" as a prefix: audio-new and audio.new.
+ writeTrashFile("audi", "foo", "foo");
+ writeTrashFile("audio-new", "foo", "foo");
+ writeTrashFile("audio.new", "foo", "foo");
+ writeTrashFile("audio", "foo", "foo");
+ writeTrashFile("audio_new", "foo", "foo");
+ Status stat = git.status().call();
+ assertEquals(Sets.of("audi", "audio-new", "audio.new", "audio",
+ "audio_new"), stat.getUntrackedFolders());
+ }
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
index 3d46a47ced..62824d3aec 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010, 2013 Google Inc. and others
+ * Copyright (C) 2010, 2020 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
@@ -11,12 +11,16 @@
package org.eclipse.jgit.diff;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.junit.RepositoryTestCase;
@@ -74,6 +78,17 @@ public class DiffFormatterTest extends RepositoryTestCase {
}
@Test
+ public void testDefaultRenameDetectorSettings() throws Exception {
+ RenameDetector rd = df.getRenameDetector();
+ assertNull(rd);
+ df.setDetectRenames(true);
+ rd = df.getRenameDetector();
+ assertNotNull(rd);
+ assertEquals(400, rd.getRenameLimit());
+ assertEquals(60, rd.getRenameScore());
+ }
+
+ @Test
public void testCreateFileHeader_Add() throws Exception {
ObjectId adId = blob("a\nd\n");
DiffEntry ent = DiffEntry.add("FOO", adId);
@@ -455,6 +470,58 @@ public class DiffFormatterTest extends RepositoryTestCase {
}
@Test
+ public void testTrackedFileInIgnoredFolderUnchanged()
+ throws Exception {
+ commitFile("empty/empty/foo", "", "master");
+ commitFile(".gitignore", "empty/*", "master");
+ try (Git git = new Git(db)) {
+ Status status = git.status().call();
+ assertTrue(status.isClean());
+ }
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DiffFormatter dfmt = new DiffFormatter(os)) {
+ dfmt.setRepository(db);
+ dfmt.format(new DirCacheIterator(db.readDirCache()),
+ new FileTreeIterator(db));
+ dfmt.flush();
+
+ String actual = os.toString("UTF-8");
+
+ assertEquals("", actual);
+ }
+ }
+
+ @Test
+ public void testTrackedFileInIgnoredFolderChanged()
+ throws Exception {
+ String expectedDiff = "diff --git a/empty/empty/foo b/empty/empty/foo\n"
+ + "index e69de29..5ea2ed4 100644\n" //
+ + "--- a/empty/empty/foo\n" //
+ + "+++ b/empty/empty/foo\n" //
+ + "@@ -0,0 +1 @@\n" //
+ + "+changed\n";
+
+ commitFile("empty/empty/foo", "", "master");
+ commitFile(".gitignore", "empty/*", "master");
+ try (Git git = new Git(db)) {
+ Status status = git.status().call();
+ assertTrue(status.isClean());
+ }
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DiffFormatter dfmt = new DiffFormatter(os)) {
+ writeTrashFile("empty/empty/foo", "changed\n");
+ dfmt.setRepository(db);
+ dfmt.format(new DirCacheIterator(db.readDirCache()),
+ new FileTreeIterator(db));
+ dfmt.flush();
+
+ String actual = os.toString("UTF-8");
+
+ assertEquals(expectedDiff, actual);
+ }
+ }
+
+ @Test
public void testDiffAutoCrlfSmallFile() throws Exception {
String content = "01234\r\n01234\r\n01234\r\n";
String expectedDiff = "diff --git a/test.txt b/test.txt\n"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheAfterCloneTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheAfterCloneTest.java
new file mode 100644
index 0000000000..f210760bf5
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheAfterCloneTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 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.dircache;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.eclipse.jgit.api.CloneCommand;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.ResetCommand.ResetType;
+import org.eclipse.jgit.dircache.DirCache.DirCacheVersion;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.SystemReader;
+import org.junit.Test;
+
+/**
+ * Tests for initial DirCache version after a clone or after a mixed or hard
+ * reset.
+ */
+public class DirCacheAfterCloneTest extends RepositoryTestCase {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ try (Git git = new Git(db)) {
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
+ }
+
+ private DirCacheVersion cloneAndCheck(Set<DirCacheVersion> expected)
+ throws Exception {
+ File directory = createTempDirectory("testCloneRepository");
+ CloneCommand command = Git.cloneRepository();
+ command.setDirectory(directory);
+ command.setURI("file://" + db.getWorkTree().getAbsolutePath());
+ Git git2 = command.call();
+ addRepoToClose(git2.getRepository());
+ assertNotNull(git2);
+ DirCache dc = DirCache.read(git2.getRepository());
+ DirCacheVersion version = dc.getVersion();
+ assertTrue(expected.contains(version));
+ return version;
+ }
+
+ @Test
+ public void testCloneV3OrV2() throws Exception {
+ cloneAndCheck(EnumSet.of(DirCacheVersion.DIRC_VERSION_MINIMUM,
+ DirCacheVersion.DIRC_VERSION_EXTENDED));
+ }
+
+ @Test
+ public void testCloneV4() throws Exception {
+ StoredConfig cfg = SystemReader.getInstance().getUserConfig();
+ cfg.load();
+ cfg.setInt("index", null, "version", 4);
+ cfg.save();
+ cloneAndCheck(EnumSet.of(DirCacheVersion.DIRC_VERSION_PATHCOMPRESS));
+ }
+
+ @Test
+ public void testCloneV4manyFiles() throws Exception {
+ StoredConfig cfg = SystemReader.getInstance().getUserConfig();
+ cfg.load();
+ cfg.setBoolean("feature", null, "manyFiles", true);
+ cfg.save();
+ cloneAndCheck(EnumSet.of(DirCacheVersion.DIRC_VERSION_PATHCOMPRESS));
+ }
+
+ @Test
+ public void testCloneV3CommitNoVersionChange() throws Exception {
+ DirCacheVersion initial = cloneAndCheck(
+ EnumSet.of(DirCacheVersion.DIRC_VERSION_MINIMUM,
+ DirCacheVersion.DIRC_VERSION_EXTENDED));
+ StoredConfig cfg = db.getConfig();
+ cfg.setInt("index", null, "version", 4);
+ cfg.save();
+ try (Git git = new Git(db)) {
+ writeTrashFile("Test.txt2", "Hello again");
+ git.add().addFilepattern("Test.txt2").call();
+ git.commit().setMessage("Second commit").call();
+ }
+ assertEquals("DirCache version should be unchanged", initial,
+ DirCache.read(db).getVersion());
+ }
+
+ @Test
+ public void testCloneV3ResetHardVersionChange() throws Exception {
+ cloneAndCheck(EnumSet.of(DirCacheVersion.DIRC_VERSION_MINIMUM,
+ DirCacheVersion.DIRC_VERSION_EXTENDED));
+ StoredConfig cfg = db.getConfig();
+ cfg.setInt("index", null, "version", 4);
+ cfg.save();
+ FileUtils.delete(new File(db.getDirectory(), "index"));
+ try (Git git = new Git(db)) {
+ git.reset().setMode(ResetType.HARD).call();
+ }
+ assertEquals("DirCache version should have changed",
+ DirCacheVersion.DIRC_VERSION_PATHCOMPRESS,
+ DirCache.read(db).getVersion());
+ }
+
+ @Test
+ public void testCloneV3ResetMixedVersionChange() throws Exception {
+ cloneAndCheck(EnumSet.of(DirCacheVersion.DIRC_VERSION_MINIMUM,
+ DirCacheVersion.DIRC_VERSION_EXTENDED));
+ StoredConfig cfg = db.getConfig();
+ cfg.setInt("index", null, "version", 4);
+ cfg.save();
+ FileUtils.delete(new File(db.getDirectory(), "index"));
+ try (Git git = new Git(db)) {
+ git.reset().setMode(ResetType.MIXED).call();
+ }
+ assertEquals("DirCache version should have changed",
+ DirCacheVersion.DIRC_VERSION_PATHCOMPRESS,
+ DirCache.read(db).getVersion());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
index c57cb263d1..6d4d0b4ab3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010, Google Inc. and others
+ * Copyright (C) 2008, 2020, 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
@@ -28,6 +28,7 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import org.eclipse.jgit.dircache.DirCache.DirCacheVersion;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
@@ -188,6 +189,28 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
assertArrayEquals(expectedBytes, indexBytes);
}
+ @Test
+ public void testReadWriteV4() throws Exception {
+ final File file = pathOf("gitgit.index.v4");
+ final DirCache dc = new DirCache(file, FS.DETECTED);
+ dc.read();
+ assertEquals(DirCacheVersion.DIRC_VERSION_PATHCOMPRESS,
+ dc.getVersion());
+ assertEquals(5, dc.getEntryCount());
+ assertV4TreeEntry(0, "src/org/eclipse/jgit/atest/foo.txt", false, dc);
+ assertV4TreeEntry(1, "src/org/eclipse/jgit/atest/foobar.txt", false,
+ dc);
+ assertV4TreeEntry(2, "src/org/eclipse/jgit/other/bar.txt", true, dc);
+ assertV4TreeEntry(3, "test.txt", false, dc);
+ assertV4TreeEntry(4, "test.txt2", false, dc);
+
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ dc.writeTo(null, bos);
+ final byte[] indexBytes = bos.toByteArray();
+ final byte[] expectedBytes = IO.readFully(file);
+ assertArrayEquals(expectedBytes, indexBytes);
+ }
+
private static void assertV3TreeEntry(int indexPosition, String path,
boolean skipWorkTree, boolean intentToAdd, DirCache dc) {
final DirCacheEntry entry = dc.getEntry(indexPosition);
@@ -196,6 +219,13 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
assertEquals(intentToAdd, entry.isIntentToAdd());
}
+ private static void assertV4TreeEntry(int indexPosition, String path,
+ boolean skipWorkTree, DirCache dc) {
+ final DirCacheEntry entry = dc.getEntry(indexPosition);
+ assertEquals(path, entry.getPathString());
+ assertEquals(skipWorkTree, entry.isSkipWorkTree());
+ }
+
private static File pathOf(String name) {
return JGitTestUtil.getTestResourceFile(name);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
index f21c7f854f..8e84dfa318 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, Google Inc. and others
+ * Copyright (C) 2009, 2020 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
@@ -11,14 +11,25 @@
package org.eclipse.jgit.dircache;
import static java.time.Instant.EPOCH;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.time.Instant;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jgit.dircache.DirCache.DirCacheVersion;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.MutableInteger;
import org.junit.Test;
public class DirCacheEntryTest {
@@ -47,6 +58,95 @@ public class DirCacheEntryTest {
}
}
+ private static void checkPath(DirCacheVersion indexVersion,
+ DirCacheEntry previous, String name) throws IOException {
+ DirCacheEntry dce = new DirCacheEntry(name);
+ long now = System.currentTimeMillis();
+ long anHourAgo = now - TimeUnit.HOURS.toMillis(1);
+ dce.setLastModified(Instant.ofEpochMilli(anHourAgo));
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ dce.write(out, indexVersion, previous);
+ byte[] raw = out.toByteArray();
+ MessageDigest md0 = Constants.newMessageDigest();
+ md0.update(raw);
+ ByteArrayInputStream in = new ByteArrayInputStream(raw);
+ MutableInteger infoAt = new MutableInteger();
+ byte[] sharedInfo = new byte[raw.length];
+ MessageDigest md = Constants.newMessageDigest();
+ DirCacheEntry read = new DirCacheEntry(sharedInfo, infoAt, in, md,
+ Instant.ofEpochMilli(now), indexVersion, previous);
+ assertEquals("Paths of length " + name.length() + " should match", name,
+ read.getPathString());
+ assertEquals("Should have been fully read", -1, in.read());
+ assertArrayEquals("Digests should match", md0.digest(),
+ md.digest());
+ }
+
+ @Test
+ public void testLongPath() throws Exception {
+ StringBuilder name = new StringBuilder(4094 + 16);
+ for (int i = 0; i < 4094; i++) {
+ name.append('a');
+ }
+ for (int j = 0; j < 16; j++) {
+ checkPath(DirCacheVersion.DIRC_VERSION_EXTENDED, null,
+ name.toString());
+ name.append('b');
+ }
+ }
+
+ @Test
+ public void testLongPathV4() throws Exception {
+ StringBuilder name = new StringBuilder(4094 + 16);
+ for (int i = 0; i < 4094; i++) {
+ name.append('a');
+ }
+ DirCacheEntry previous = new DirCacheEntry(name.toString());
+ for (int j = 0; j < 16; j++) {
+ checkPath(DirCacheVersion.DIRC_VERSION_PATHCOMPRESS, previous,
+ name.toString());
+ name.append('b');
+ }
+ }
+
+ @Test
+ public void testShortPath() throws Exception {
+ StringBuilder name = new StringBuilder(1 + 16);
+ name.append('a');
+ for (int j = 0; j < 16; j++) {
+ checkPath(DirCacheVersion.DIRC_VERSION_EXTENDED, null,
+ name.toString());
+ name.append('b');
+ }
+ }
+
+ @Test
+ public void testShortPathV4() throws Exception {
+ StringBuilder name = new StringBuilder(1 + 16);
+ name.append('a');
+ DirCacheEntry previous = new DirCacheEntry(name.toString());
+ for (int j = 0; j < 16; j++) {
+ checkPath(DirCacheVersion.DIRC_VERSION_PATHCOMPRESS, previous,
+ name.toString());
+ name.append('b');
+ }
+ }
+
+ @Test
+ public void testPathV4() throws Exception {
+ StringBuilder name = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ name.append('a');
+ }
+ DirCacheEntry previous = new DirCacheEntry(name.toString());
+ for (int j = 0; j < 20; j++) {
+ name.setLength(name.length() - 1);
+ String newName = name.toString() + "bbb";
+ checkPath(DirCacheVersion.DIRC_VERSION_PATHCOMPRESS, previous,
+ newName);
+ }
+ }
+
@SuppressWarnings("unused")
@Test
public void testCreate_ByStringPath() {
@@ -142,6 +242,46 @@ public class DirCacheEntryTest {
}
@Test
+ public void testSetStage() {
+ DirCacheEntry e = new DirCacheEntry("some/path", DirCacheEntry.STAGE_1);
+ e.setAssumeValid(true);
+ e.setCreationTime(2L);
+ e.setFileMode(FileMode.EXECUTABLE_FILE);
+ e.setLastModified(EPOCH.plusMillis(3L));
+ e.setLength(100L);
+ e.setObjectId(ObjectId
+ .fromString("0123456789012345678901234567890123456789"));
+ e.setUpdateNeeded(true);
+ e.setStage(DirCacheEntry.STAGE_2);
+
+ assertTrue(e.isAssumeValid());
+ assertEquals(2L, e.getCreationTime());
+ assertEquals(
+ ObjectId.fromString("0123456789012345678901234567890123456789"),
+ e.getObjectId());
+ assertEquals(FileMode.EXECUTABLE_FILE, e.getFileMode());
+ assertEquals(EPOCH.plusMillis(3L), e.getLastModifiedInstant());
+ assertEquals(100L, e.getLength());
+ assertEquals(DirCacheEntry.STAGE_2, e.getStage());
+ assertTrue(e.isUpdateNeeded());
+ assertEquals("some/path", e.getPathString());
+
+ e.setStage(DirCacheEntry.STAGE_0);
+
+ assertTrue(e.isAssumeValid());
+ assertEquals(2L, e.getCreationTime());
+ assertEquals(
+ ObjectId.fromString("0123456789012345678901234567890123456789"),
+ e.getObjectId());
+ assertEquals(FileMode.EXECUTABLE_FILE, e.getFileMode());
+ assertEquals(EPOCH.plusMillis(3L), e.getLastModifiedInstant());
+ assertEquals(100L, e.getLength());
+ assertEquals(DirCacheEntry.STAGE_0, e.getStage());
+ assertTrue(e.isUpdateNeeded());
+ assertEquals("some/path", e.getPathString());
+ }
+
+ @Test
public void testCopyMetaDataWithStage() {
copyMetaDataHelper(false);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
index 39a1f01803..5778d28d6f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, Robin Rosenberg and others
+ * Copyright (C) 2011, 2020 Robin Rosenberg and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -124,6 +124,32 @@ public class DirCachePathEditTest {
}
@Test
+ public void testPathEditWithStagesAndReset() throws Exception {
+ DirCache dc = DirCache.newInCore();
+ DirCacheBuilder builder = new DirCacheBuilder(dc, 3);
+ builder.add(createEntry("a", DirCacheEntry.STAGE_1));
+ builder.add(createEntry("a", DirCacheEntry.STAGE_2));
+ builder.add(createEntry("a", DirCacheEntry.STAGE_3));
+ builder.finish();
+
+ DirCacheEditor editor = dc.editor();
+ PathEdit edit = new PathEdit("a") {
+
+ @Override
+ public void apply(DirCacheEntry ent) {
+ ent.setStage(DirCacheEntry.STAGE_0);
+ }
+ };
+ editor.add(edit);
+ editor.finish();
+
+ assertEquals(1, dc.getEntryCount());
+ DirCacheEntry entry = dc.getEntry(0);
+ assertEquals("a", entry.getPathString());
+ assertEquals(DirCacheEntry.STAGE_0, entry.getStage());
+ }
+
+ @Test
public void testFileReplacesTree() throws Exception {
DirCache dc = DirCache.newInCore();
DirCacheEditor editor = dc.editor();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriterTest.java
new file mode 100644
index 0000000000..4238ee6bf0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriterTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020, Google LLC 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
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.FetchResult;
+import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.TransportBundleStream;
+import org.eclipse.jgit.transport.URIish;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DfsBundleWriterTest {
+ private TestRepository<InMemoryRepository> git;
+
+ private InMemoryRepository repo;
+
+ @Before
+ public void setUp() throws IOException {
+ DfsRepositoryDescription desc = new DfsRepositoryDescription("test");
+ git = new TestRepository<>(new InMemoryRepository(desc));
+ repo = git.getRepository();
+ }
+
+ @Test
+ public void testRepo() throws Exception {
+ RevCommit commit0 = git.commit().message("0").create();
+ RevCommit commit1 = git.commit().message("1").parent(commit0).create();
+ git.update("master", commit1);
+
+ RevCommit commit2 = git.commit().message("0").create();
+
+ byte[] bundle = makeBundle();
+ try (Repository newRepo = new InMemoryRepository(
+ new DfsRepositoryDescription("copy"))) {
+ fetchFromBundle(newRepo, bundle);
+ Ref ref = newRepo.exactRef("refs/heads/master");
+ assertNotNull(ref);
+ assertEquals(commit1.toObjectId(), ref.getObjectId());
+
+ // Unreferenced objects are included as well.
+ assertTrue(newRepo.getObjectDatabase().has(commit2));
+ }
+ }
+
+ private byte[] makeBundle() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ DfsBundleWriter.writeEntireRepositoryAsBundle(
+ NullProgressMonitor.INSTANCE, out, repo);
+ return out.toByteArray();
+ }
+
+ private static FetchResult fetchFromBundle(Repository newRepo,
+ byte[] bundle) throws Exception {
+ URIish uri = new URIish("in-memory://");
+ ByteArrayInputStream in = new ByteArrayInputStream(bundle);
+ RefSpec rs = new RefSpec("refs/heads/*:refs/heads/*");
+ Set<RefSpec> refs = Collections.singleton(rs);
+ try (TransportBundleStream transport = new TransportBundleStream(
+ newRepo, uri, in)) {
+ return transport.fetch(NullProgressMonitor.INSTANCE, refs);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index e8d1cd3d7e..d007dd4511 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
@@ -80,6 +80,29 @@ public class GcBasicPackingTest extends GcTestCase {
}
@Theory
+ public void testPack2Commits_noPackFolder(boolean aggressive) throws Exception {
+ File packDir = repo.getObjectDatabase().getPackDirectory();
+ assertTrue(packDir.delete());
+
+ BranchBuilder bb = tr.branch("refs/heads/master");
+ bb.commit().add("A", "A").add("B", "B").create();
+ bb.commit().add("A", "A2").add("B", "B2").create();
+
+ stats = gc.getStatistics();
+ assertEquals(8, stats.numberOfLooseObjects);
+ assertEquals(0, stats.numberOfPackedObjects);
+ configureGc(gc, aggressive);
+ gc.gc();
+ stats = gc.getStatistics();
+ assertEquals(0, stats.numberOfLooseObjects);
+ assertEquals(8, stats.numberOfPackedObjects);
+ assertEquals(1, stats.numberOfPackFiles);
+ assertEquals(2, stats.numberOfBitmaps);
+
+ assertTrue(packDir.exists());
+ }
+
+ @Theory
public void testPackAllObjectsInOnePack(boolean aggressive)
throws Exception {
tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B")
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
index 84d364b985..c5c316d357 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcOrphanFilesTest.java
@@ -24,10 +24,14 @@ public class GcOrphanFilesTest extends GcTestCase {
private static final String BITMAP_File_1 = PACK + "-1.bitmap";
+ private static final String BITMAP_File_2 = PACK + "-2.bitmap";
+
private static final String IDX_File_2 = PACK + "-2.idx";
private static final String IDX_File_malformed = PACK + "-1234idx";
+ private static final String KEEP_File_2 = PACK + "-2.keep";
+
private static final String PACK_File_2 = PACK + "-2.pack";
private static final String PACK_File_3 = PACK + "-3.pack";
@@ -72,6 +76,22 @@ public class GcOrphanFilesTest extends GcTestCase {
assertTrue(new File(packDir, IDX_File_malformed).exists());
}
+ @Test
+ public void keepPreventsDeletionOfIndexFilesForMissingPackFile()
+ throws Exception {
+ createFileInPackFolder(BITMAP_File_1);
+ createFileInPackFolder(IDX_File_2);
+ createFileInPackFolder(BITMAP_File_2);
+ createFileInPackFolder(KEEP_File_2);
+ createFileInPackFolder(PACK_File_3);
+ gc.gc();
+ assertFalse(new File(packDir, BITMAP_File_1).exists());
+ assertTrue(new File(packDir, BITMAP_File_2).exists());
+ assertTrue(new File(packDir, IDX_File_2).exists());
+ assertTrue(new File(packDir, KEEP_File_2).exists());
+ assertTrue(new File(packDir, PACK_File_3).exists());
+ }
+
private void createFileInPackFolder(String fileName) throws IOException {
if (!packDir.exists() || !packDir.isDirectory()) {
assertTrue(packDir.mkdirs());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
index fe05fbae39..910b928864 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexTestCase.java
@@ -12,13 +12,17 @@ package org.eclipse.jgit.internal.storage.file;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.junit.Test;
@@ -51,6 +55,13 @@ public abstract class PackIndexTestCase extends RepositoryTestCase {
public abstract File getFileForPackdf2982f28();
/**
+ * Return file with appropriate index version for bad fanout table test.
+ *
+ * @return file with index
+ */
+ public abstract File getFileForBadFanoutTable();
+
+ /**
* Verify CRC32 support.
*
* @throws MissingObjectException
@@ -158,4 +169,15 @@ public abstract class PackIndexTestCase extends RepositoryTestCase {
.name());
}
+ @Test
+ public void testBadFanoutTable() {
+ IOException ex = assertThrows(IOException.class, () -> {
+ try (FileInputStream fis = new FileInputStream(
+ getFileForBadFanoutTable())) {
+ PackIndex.read(fis);
+ }
+ });
+ assertEquals(JGitText.get().indexFileIsTooLargeForJgit,
+ ex.getMessage());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV1Test.java
index e41ded7d71..c4f637276c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV1Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV1Test.java
@@ -35,6 +35,11 @@ public class PackIndexV1Test extends PackIndexTestCase {
"pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idx");
}
+ @Override
+ public File getFileForBadFanoutTable() {
+ return JGitTestUtil.getTestResourceFile("pack-bad-fanout-table.idx");
+ }
+
/**
* Verify CRC32 - V1 should not index anything.
*
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV2Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV2Test.java
index c1da54721f..1d179abd86 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV2Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackIndexV2Test.java
@@ -35,6 +35,11 @@ public class PackIndexV2Test extends PackIndexTestCase {
"pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2");
}
+ @Override
+ public File getFileForBadFanoutTable() {
+ return JGitTestUtil.getTestResourceFile("pack-bad-fanout-table.idxV2");
+ }
+
/**
* Verify CRC32 indexing.
*
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
index a246ac9e9c..0a03fc3523 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java
@@ -329,21 +329,21 @@ public class MergedReftableTest {
public void overlappedUpdateIndices() throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
ReftableWriter writer = new ReftableWriter(buf)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(3)
+ .setMinUpdateIndex(2)
+ .setMaxUpdateIndex(4)
.begin();
- writer.writeRef(ref("refs/heads/a", 1), 1);
- writer.writeRef(ref("refs/heads/b", 2), 3);
+ writer.writeRef(ref("refs/heads/a", 10), 2);
+ writer.writeRef(ref("refs/heads/b", 20), 4);
writer.finish();
byte[] base = buf.toByteArray();
buf = new ByteArrayOutputStream();
writer = new ReftableWriter(buf)
- .setMinUpdateIndex(2)
- .setMaxUpdateIndex(4)
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(3)
.begin();
- writer.writeRef(ref("refs/heads/a", 10), 2);
- writer.writeRef(ref("refs/heads/b", 20), 4);
+ writer.writeRef(ref("refs/heads/a", 1), 1);
+ writer.writeRef(ref("refs/heads/b", 2), 3);
writer.finish();
byte[] delta = buf.toByteArray();
@@ -368,21 +368,21 @@ public class MergedReftableTest {
public void enclosedUpdateIndices() throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
ReftableWriter writer = new ReftableWriter(buf)
- .setMinUpdateIndex(1)
- .setMaxUpdateIndex(4)
+ .setMinUpdateIndex(2)
+ .setMaxUpdateIndex(3)
.begin();
- writer.writeRef(ref("refs/heads/a", 1), 1);
- writer.writeRef(ref("refs/heads/b", 20), 4);
+ writer.writeRef(ref("refs/heads/a", 10), 2);
+ writer.writeRef(ref("refs/heads/b", 2), 3);
writer.finish();
byte[] base = buf.toByteArray();
buf = new ByteArrayOutputStream();
writer = new ReftableWriter(buf)
- .setMinUpdateIndex(2)
- .setMaxUpdateIndex(3)
+ .setMinUpdateIndex(1)
+ .setMaxUpdateIndex(4)
.begin();
- writer.writeRef(ref("refs/heads/a", 10), 2);
- writer.writeRef(ref("refs/heads/b", 2), 3);
+ writer.writeRef(ref("refs/heads/a", 1), 1);
+ writer.writeRef(ref("refs/heads/b", 20), 4);
writer.finish();
byte[] delta = buf.toByteArray();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java
index 26294c7714..dee58f9cfc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java
@@ -13,7 +13,7 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -24,6 +24,32 @@ import org.junit.Test;
public class CommitBuilderTest {
+ // @formatter:off
+ private static final String SIGNATURE = "-----BEGIN PGP SIGNATURE-----\n" +
+ "Version: BCPG v1.60\n" +
+ "\n" +
+ "iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" +
+ "opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" +
+ "gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" +
+ "uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" +
+ "3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" +
+ "IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" +
+ "=b9OI\n" +
+ "-----END PGP SIGNATURE-----";
+
+ private static final String EXPECTED = "-----BEGIN PGP SIGNATURE-----\n" +
+ " Version: BCPG v1.60\n" +
+ " \n" +
+ " iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" +
+ " opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" +
+ " gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" +
+ " uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" +
+ " 3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" +
+ " IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" +
+ " =b9OI\n" +
+ " -----END PGP SIGNATURE-----";
+ // @formatter:on
+
private void assertGpgSignatureStringOutcome(String signature,
String expectedOutcome) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -33,47 +59,37 @@ public class CommitBuilderTest {
}
@Test
- public void writeGpgSignatureString_1() throws Exception {
- // @formatter:off
- String signature = "-----BEGIN PGP SIGNATURE-----\n" +
- "Version: BCPG v1.60\n" +
- "\n" +
- "iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" +
- "opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" +
- "gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" +
- "uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" +
- "3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" +
- "IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" +
- "=b9OI\n" +
- "-----END PGP SIGNATURE-----";
- String expectedOutcome = "-----BEGIN PGP SIGNATURE-----\n" +
- " Version: BCPG v1.60\n" +
- " \n" +
- " iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" +
- " opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" +
- " gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" +
- " uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" +
- " 3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" +
- " IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" +
- " =b9OI\n" +
- " -----END PGP SIGNATURE-----";
- // @formatter:on
- assertGpgSignatureStringOutcome(signature, expectedOutcome);
+ public void writeGpgSignatureString() throws Exception {
+ assertGpgSignatureStringOutcome(SIGNATURE, EXPECTED);
+ }
+
+ @Test
+ public void writeGpgSignatureStringTrailingLF() throws Exception {
+ assertGpgSignatureStringOutcome(SIGNATURE + '\n', EXPECTED);
+ }
+
+ @Test
+ public void writeGpgSignatureStringCRLF() throws Exception {
+ assertGpgSignatureStringOutcome(SIGNATURE.replaceAll("\n", "\r\n"),
+ EXPECTED);
+ }
+
+ @Test
+ public void writeGpgSignatureStringTrailingCRLF() throws Exception {
+ assertGpgSignatureStringOutcome(
+ SIGNATURE.replaceAll("\n", "\r\n") + "\r\n", EXPECTED);
}
@Test
public void writeGpgSignatureString_failsForNonAscii() throws Exception {
String signature = "Ü Ä";
- try {
- CommitBuilder.writeGpgSignatureString(signature,
- new ByteArrayOutputStream());
- fail("Exception expected");
- } catch (IllegalArgumentException e) {
- // good
- String message = MessageFormat.format(JGitText.get().notASCIIString,
- signature);
- assertEquals(message, e.getMessage());
- }
+ IllegalArgumentException e = assertThrows(
+ IllegalArgumentException.class,
+ () -> CommitBuilder.writeGpgSignatureString(signature,
+ new ByteArrayOutputStream()));
+ String message = MessageFormat.format(JGitText.get().notASCIIString,
+ signature);
+ assertEquals(message, e.getMessage());
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index a272c8f2ee..b943486b1b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -2,41 +2,13 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008-2011, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008-2011, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2010-2011, Christian Halstrick <christian.halstrick@sap.com>
- * and other copyright owners as documented in the project's IP log.
+ * Copyright (C) 2010, 2020 Christian Halstrick <christian.halstrick@sap.com> and others
*
* This program and the accompanying materials are made available under the
- * terms of the Eclipse Distribution License v1.0 which accompanies this
- * distribution, is reproduced below, and is available at
- * http://www.eclipse.org/org/documents/edl-v10.php
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
*
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.lib;
@@ -85,6 +57,7 @@ import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.StringUtils;
import org.junit.Assume;
import org.junit.Test;
@@ -284,6 +257,86 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
}
}
+ private void checkoutLineEndings(String inIndex, String expected,
+ String attributes) throws Exception {
+ try (Git git = new Git(db);
+ TestRepository<Repository> db_t = new TestRepository<>(db)) {
+ BranchBuilder master = db_t.branch("master");
+ master.commit().add("f", inIndex).message("m0").create();
+ if (!StringUtils.isEmptyOrNull(attributes)) {
+ master.commit().add(".gitattributes", attributes)
+ .message("attributes").create();
+ }
+ File f = new File(db.getWorkTree(), "f");
+ assertFalse(f.exists());
+ git.checkout().setName("master").call();
+ assertTrue(f.exists());
+ checkFile(f, expected);
+ }
+ }
+
+ @Test
+ public void testCheckoutWithCRLF() throws Exception {
+ checkoutLineEndings("first line\r\nsecond line\r\n",
+ "first line\r\nsecond line\r\n", null);
+ }
+
+ @Test
+ public void testCheckoutWithCRLFAuto() throws Exception {
+ checkoutLineEndings("first line\r\nsecond line\r\n",
+ "first line\r\nsecond line\r\n", "f text=auto");
+ }
+
+ @Test
+ public void testCheckoutWithCRLFAutoEolLf() throws Exception {
+ checkoutLineEndings("first line\r\nsecond line\r\n",
+ "first line\r\nsecond line\r\n", "f text=auto eol=lf");
+ }
+
+ @Test
+ public void testCheckoutWithCRLFAutoEolNative() throws Exception {
+ checkoutLineEndings("first line\r\nsecond line\r\n",
+ "first line\r\nsecond line\r\n", "f text=auto eol=native");
+ }
+
+ @Test
+ public void testCheckoutWithCRLFAutoEolCrLf() throws Exception {
+ checkoutLineEndings("first line\r\nsecond line\r\n",
+ "first line\r\nsecond line\r\n", "f text=auto eol=crlf");
+ }
+
+ @Test
+ public void testCheckoutWithLF() throws Exception {
+ checkoutLineEndings("first line\nsecond line\n",
+ "first line\nsecond line\n", null);
+ }
+
+ @Test
+ public void testCheckoutWithLFAuto() throws Exception {
+ checkoutLineEndings("first line\nsecond line\n",
+ "first line\nsecond line\n", "f text=auto");
+ }
+
+ @Test
+ public void testCheckoutWithLFAutoEolLf() throws Exception {
+ checkoutLineEndings("first line\nsecond line\n",
+ "first line\nsecond line\n", "f text=auto eol=lf");
+ }
+
+ @Test
+ public void testCheckoutWithLFAutoEolNative() throws Exception {
+ checkoutLineEndings(
+ "first line\nsecond line\n", "first line\nsecond line\n"
+ .replaceAll("\n", System.lineSeparator()),
+ "f text=auto eol=native");
+ }
+
+ @Test
+ public void testCheckoutWithLFAutoEolCrLf() throws Exception {
+ checkoutLineEndings("first line\nsecond line\n",
+ "first line\r\nsecond line\r\n", "f text=auto eol=crlf");
+ }
+
private DirCacheCheckout resetHard(RevCommit commit)
throws NoWorkTreeException,
CorruptObjectException, IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/logging/PerformanceLogContextTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/logging/PerformanceLogContextTest.java
new file mode 100644
index 0000000000..f3c1ddec8a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/logging/PerformanceLogContextTest.java
@@ -0,0 +1,95 @@
+package org.eclipse.jgit.logging;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import java.util.List;
+
+/**
+ * Tests for performance log context utilities.
+ */
+public class PerformanceLogContextTest {
+
+ @Test
+ public void testAddEvent() {
+ PerformanceLogRecord record = new PerformanceLogRecord("record", 0);
+ PerformanceLogContext.getInstance().addEvent(record);
+
+ List<PerformanceLogRecord> eventRecords = PerformanceLogContext
+ .getInstance().getEventRecords();
+ assertTrue(eventRecords.contains(record));
+ assertEquals(1, eventRecords.size());
+ }
+
+ @Test
+ public void testCleanEvents() {
+ PerformanceLogRecord record1 = new PerformanceLogRecord("record1", 0);
+ PerformanceLogContext.getInstance().addEvent(record1);
+
+ PerformanceLogRecord record2 = new PerformanceLogRecord("record2", 0);
+ PerformanceLogContext.getInstance().addEvent(record2);
+
+ PerformanceLogContext.getInstance().cleanEvents();
+ List<PerformanceLogRecord> eventRecords = PerformanceLogContext
+ .getInstance().getEventRecords();
+ assertEquals(0, eventRecords.size());
+ }
+
+ @Test
+ public void testAddEventsTwoThreads() throws InterruptedException {
+ TestRunnable runnable1 = new TestRunnable("record1", 1);
+ TestRunnable runnable2 = new TestRunnable("record2", 2);
+
+ Thread thread1 = new Thread(runnable1);
+ Thread thread2 = new Thread(runnable2);
+
+ thread1.start();
+ thread2.start();
+
+ thread1.join();
+ thread2.join();
+ assertEquals(1, runnable1.getEventRecordsCount());
+ assertEquals(1, runnable2.getEventRecordsCount());
+ assertFalse(runnable1.isThrown());
+ assertFalse(runnable2.isThrown());
+ }
+
+ private static class TestRunnable implements Runnable {
+ private String name;
+
+ private long durationMs;
+
+ private long eventRecordsCount;
+
+ private boolean thrown = false;
+
+ public TestRunnable(String name, long durationMs) {
+ this.name = name;
+ this.durationMs = durationMs;
+ }
+
+ public boolean isThrown() {
+ return thrown;
+ }
+
+ public long getEventRecordsCount() {
+ return eventRecordsCount;
+ }
+
+ @Override
+ public void run() {
+ PerformanceLogRecord record = new PerformanceLogRecord(name,
+ durationMs);
+ try {
+ PerformanceLogContext.getInstance().addEvent(record);
+ eventRecordsCount = PerformanceLogContext.getInstance()
+ .getEventRecords().size();
+ PerformanceLogContext.getInstance().cleanEvents();
+ } catch (Exception e) {
+ thrown = true;
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/GitlinkMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/GitlinkMergeTest.java
new file mode 100644
index 0000000000..f410960bec
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/GitlinkMergeTest.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2020, Google LLC 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
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.merge;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.junit.Test;
+
+public class GitlinkMergeTest extends SampleDataRepositoryTestCase {
+ private static final String LINK_ID1 = "DEADBEEFDEADBEEFBABEDEADBEEFDEADBEEFBABE";
+ private static final String LINK_ID2 = "DEADDEADDEADDEADDEADDEADDEADDEADDEADDEAD";
+ private static final String LINK_ID3 = "BEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEF";
+
+ private static final String SUBMODULE_PATH = "submodule.link";
+
+ @Test
+ public void testGitLinkMerging_AddNew() throws Exception {
+ assertGitLinkValue(
+ testGitLink(null, null, LINK_ID3, newResolveMerger(), true),
+ LINK_ID3);
+ }
+
+ @Test
+ public void testGitLinkMerging_Delete() throws Exception {
+ assertGitLinkDoesntExist(testGitLink(LINK_ID1, LINK_ID1, null,
+ newResolveMerger(), true));
+ }
+
+ @Test
+ public void testGitLinkMerging_UpdateDelete() throws Exception {
+ testGitLink(LINK_ID1, LINK_ID2, null, newResolveMerger(), false);
+ }
+
+ @Test
+ public void testGitLinkMerging_DeleteUpdate() throws Exception {
+ testGitLink(LINK_ID1, null, LINK_ID3, newResolveMerger(), false);
+ }
+
+ @Test
+ public void testGitLinkMerging_UpdateUpdate() throws Exception {
+ testGitLink(LINK_ID1, LINK_ID2, LINK_ID3, newResolveMerger(), false);
+ }
+
+ @Test
+ public void testGitLinkMerging_bothAddedSameLink() throws Exception {
+ assertGitLinkValue(
+ testGitLink(null, LINK_ID2, LINK_ID2, newResolveMerger(), true),
+ LINK_ID2);
+ }
+
+ @Test
+ public void testGitLinkMerging_bothAddedDifferentLink() throws Exception {
+ testGitLink(null, LINK_ID2, LINK_ID3, newResolveMerger(), false);
+ }
+
+ @Test
+ public void testGitLinkMerging_AddNew_ignoreConflicts() throws Exception {
+ assertGitLinkValue(
+ testGitLink(null, null, LINK_ID3, newIgnoreConflictMerger(),
+ true),
+ LINK_ID3);
+ }
+
+ @Test
+ public void testGitLinkMerging_Delete_ignoreConflicts() throws Exception {
+ assertGitLinkDoesntExist(testGitLink(LINK_ID1, LINK_ID1, null,
+ newIgnoreConflictMerger(), true));
+ }
+
+ @Test
+ public void testGitLinkMerging_UpdateDelete_ignoreConflicts()
+ throws Exception {
+ assertGitLinkValue(testGitLink(LINK_ID1, LINK_ID2, null,
+ newIgnoreConflictMerger(), true), LINK_ID2);
+ }
+
+ @Test
+ public void testGitLinkMerging_DeleteUpdate_ignoreConflicts()
+ throws Exception {
+ assertGitLinkDoesntExist(testGitLink(LINK_ID1, null, LINK_ID3,
+ newIgnoreConflictMerger(), true));
+ }
+
+ @Test
+ public void testGitLinkMerging_UpdateUpdate_ignoreConflicts()
+ throws Exception {
+ assertGitLinkValue(testGitLink(LINK_ID1, LINK_ID2, LINK_ID3,
+ newIgnoreConflictMerger(), true), LINK_ID2);
+ }
+
+ @Test
+ public void testGitLinkMerging_bothAddedSameLink_ignoreConflicts()
+ throws Exception {
+ assertGitLinkValue(testGitLink(null, LINK_ID2, LINK_ID2,
+ newIgnoreConflictMerger(), true), LINK_ID2);
+ }
+
+ @Test
+ public void testGitLinkMerging_bothAddedDifferentLink_ignoreConflicts()
+ throws Exception {
+ assertGitLinkValue(testGitLink(null, LINK_ID2, LINK_ID3,
+ newIgnoreConflictMerger(), true), LINK_ID2);
+ }
+
+ protected Merger testGitLink(@Nullable String baseLink,
+ @Nullable String oursLink, @Nullable String theirsLink,
+ Merger merger, boolean shouldMerge)
+ throws Exception {
+ DirCache treeB = db.readDirCache();
+ DirCache treeO = db.readDirCache();
+ DirCache treeT = db.readDirCache();
+
+ DirCacheBuilder bTreeBuilder = treeB.builder();
+ DirCacheBuilder oTreeBuilder = treeO.builder();
+ DirCacheBuilder tTreeBuilder = treeT.builder();
+
+ maybeAddLink(bTreeBuilder, baseLink);
+ maybeAddLink(oTreeBuilder, oursLink);
+ maybeAddLink(tTreeBuilder, theirsLink);
+
+ bTreeBuilder.finish();
+ oTreeBuilder.finish();
+ tTreeBuilder.finish();
+
+ ObjectInserter ow = db.newObjectInserter();
+ ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ boolean merge = merger.merge(new ObjectId[] { o, t });
+ assertEquals(Boolean.valueOf(shouldMerge), Boolean.valueOf(merge));
+
+ return merger;
+ }
+
+ private Merger newResolveMerger() {
+ return MergeStrategy.RESOLVE.newMerger(db, true);
+ }
+
+ private Merger newIgnoreConflictMerger() {
+ return new ResolveMerger(db, true) {
+ @Override
+ protected boolean mergeImpl() throws IOException {
+ // emulate call with ignore conflicts.
+ return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
+ true);
+ }
+ };
+ }
+
+ @Test
+ public void testGitLinkMerging_blobWithLink() throws Exception {
+ DirCache treeB = db.readDirCache();
+ DirCache treeO = db.readDirCache();
+ DirCache treeT = db.readDirCache();
+
+ DirCacheBuilder bTreeBuilder = treeB.builder();
+ DirCacheBuilder oTreeBuilder = treeO.builder();
+ DirCacheBuilder tTreeBuilder = treeT.builder();
+
+ bTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob"));
+ oTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 2"));
+
+ maybeAddLink(tTreeBuilder, LINK_ID3);
+
+ bTreeBuilder.finish();
+ oTreeBuilder.finish();
+ tTreeBuilder.finish();
+
+ ObjectInserter ow = db.newObjectInserter();
+ ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
+ boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ @Test
+ public void testGitLinkMerging_linkWithBlob() throws Exception {
+ DirCache treeB = db.readDirCache();
+ DirCache treeO = db.readDirCache();
+ DirCache treeT = db.readDirCache();
+
+ DirCacheBuilder bTreeBuilder = treeB.builder();
+ DirCacheBuilder oTreeBuilder = treeO.builder();
+ DirCacheBuilder tTreeBuilder = treeT.builder();
+
+ maybeAddLink(bTreeBuilder, LINK_ID1);
+ maybeAddLink(oTreeBuilder, LINK_ID2);
+ tTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 3"));
+
+ bTreeBuilder.finish();
+ oTreeBuilder.finish();
+ tTreeBuilder.finish();
+
+ ObjectInserter ow = db.newObjectInserter();
+ ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
+ boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ @Test
+ public void testGitLinkMerging_linkWithLink() throws Exception {
+ DirCache treeB = db.readDirCache();
+ DirCache treeO = db.readDirCache();
+ DirCache treeT = db.readDirCache();
+
+ DirCacheBuilder bTreeBuilder = treeB.builder();
+ DirCacheBuilder oTreeBuilder = treeO.builder();
+ DirCacheBuilder tTreeBuilder = treeT.builder();
+
+ bTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob"));
+ maybeAddLink(oTreeBuilder, LINK_ID2);
+ maybeAddLink(tTreeBuilder, LINK_ID3);
+
+ bTreeBuilder.finish();
+ oTreeBuilder.finish();
+ tTreeBuilder.finish();
+
+ ObjectInserter ow = db.newObjectInserter();
+ ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
+ boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ @Test
+ public void testGitLinkMerging_blobWithBlobFromLink() throws Exception {
+ DirCache treeB = db.readDirCache();
+ DirCache treeO = db.readDirCache();
+ DirCache treeT = db.readDirCache();
+
+ DirCacheBuilder bTreeBuilder = treeB.builder();
+ DirCacheBuilder oTreeBuilder = treeO.builder();
+ DirCacheBuilder tTreeBuilder = treeT.builder();
+
+ maybeAddLink(bTreeBuilder, LINK_ID1);
+ oTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 2"));
+ tTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 3"));
+
+ bTreeBuilder.finish();
+ oTreeBuilder.finish();
+ tTreeBuilder.finish();
+
+ ObjectInserter ow = db.newObjectInserter();
+ ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
+ boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ @Test
+ public void testGitLinkMerging_linkBlobDeleted() throws Exception {
+ // We changed a link to a blob, others has deleted this link.
+ DirCache treeB = db.readDirCache();
+ DirCache treeO = db.readDirCache();
+ DirCache treeT = db.readDirCache();
+
+ DirCacheBuilder bTreeBuilder = treeB.builder();
+ DirCacheBuilder oTreeBuilder = treeO.builder();
+ DirCacheBuilder tTreeBuilder = treeT.builder();
+
+ maybeAddLink(bTreeBuilder, LINK_ID1);
+ oTreeBuilder.add(
+ createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 2"));
+
+ bTreeBuilder.finish();
+ oTreeBuilder.finish();
+ tTreeBuilder.finish();
+
+ ObjectInserter ow = db.newObjectInserter();
+ ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
+ boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ private void maybeAddLink(DirCacheBuilder builder,
+ @Nullable String linkId) {
+ if (linkId == null) {
+ return;
+ }
+ DirCacheEntry newLink = createGitLink(SUBMODULE_PATH,
+ ObjectId.fromString(linkId));
+ builder.add(newLink);
+ }
+
+ private void assertGitLinkValue(Merger resolveMerger, String expectedValue)
+ throws Exception {
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.reset(resolveMerger.getResultTreeId());
+
+ assertTrue(tw.next());
+ assertEquals(SUBMODULE_PATH, tw.getPathString());
+ assertEquals(ObjectId.fromString(expectedValue), tw.getObjectId(0));
+
+ assertFalse(tw.next());
+ }
+ }
+
+ private void assertGitLinkDoesntExist(Merger resolveMerger)
+ throws Exception {
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.reset(resolveMerger.getResultTreeId());
+
+ assertFalse(tw.next());
+ }
+ }
+
+ private static ObjectId commit(ObjectInserter odi, DirCache treeB,
+ ObjectId[] parentIds) throws Exception {
+ CommitBuilder c = new CommitBuilder();
+ c.setTreeId(treeB.writeTree(odi));
+ c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
+ c.setCommitter(c.getAuthor());
+ c.setParentIds(parentIds);
+ c.setMessage("Tree " + c.getTreeId().name());
+ ObjectId id = odi.insert(c);
+ odi.flush();
+ return id;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
index 7a244e1d8b..e2ac89be90 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, Robin Stocker <robin@nibor.org> and others
+ * Copyright (C) 2012, 2020 Robin Stocker <robin@nibor.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
@@ -367,6 +367,48 @@ public class MergerTest extends RepositoryTestCase {
}
@Theory
+ public void mergeConflictWithCrLfTextAuto(MergeStrategy strategy)
+ throws IOException, GitAPIException {
+ Git git = Git.wrap(db);
+ writeTrashFile("crlf.txt", "a crlf file\r\n");
+ git.add().addFilepattern("crlf.txt").call();
+ git.commit().setMessage("base").call();
+ assertEquals("[crlf.txt, mode:100644, content:a crlf file\r\n]",
+ indexState(CONTENT));
+ writeTrashFile(".gitattributes", "crlf.txt text=auto");
+ git.add().addFilepattern(".gitattributes").call();
+ git.commit().setMessage("attributes").call();
+
+ git.branchCreate().setName("brancha").call();
+
+ writeTrashFile("crlf.txt", "a crlf file\r\na second line\r\n");
+ git.add().addFilepattern("crlf.txt").call();
+ git.commit().setMessage("on master").call();
+ assertEquals(
+ "[.gitattributes, mode:100644, content:crlf.txt text=auto]"
+ + "[crlf.txt, mode:100644, content:a crlf file\r\na second line\r\n]",
+ indexState(CONTENT));
+
+ git.checkout().setName("brancha").call();
+ File testFile = writeTrashFile("crlf.txt",
+ "a crlf file\r\nanother line\r\n");
+ git.add().addFilepattern("crlf.txt").call();
+ git.commit().setMessage("on brancha").call();
+
+ MergeResult mergeResult = git.merge().setStrategy(strategy)
+ .include(db.resolve("master")).call();
+ assertEquals(MergeResult.MergeStatus.CONFLICTING,
+ mergeResult.getMergeStatus());
+ checkFile(testFile,
+ "a crlf file\r\n" //
+ + "<<<<<<< HEAD\n" //
+ + "another line\r\n" //
+ + "=======\n" //
+ + "a second line\r\n" //
+ + ">>>>>>> 8e9e704742f1bc8a41eac88aac4aeefd338b7384\n");
+ }
+
+ @Theory
public void mergeWithCrlfAutoCrlfTrue(MergeStrategy strategy)
throws IOException, GitAPIException {
Git git = Git.wrap(db);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
index 70175c8205..ea994f06aa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java
@@ -455,6 +455,7 @@ public class SubmoduleWalkTest extends RepositoryTestCase {
final CanonicalTreeParser p = new CanonicalTreeParser();
p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree());
try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) {
+ assertEquals(arbitraryName, gen.getModuleName());
assertEquals(path, gen.getPath());
assertEquals(subId, gen.getObjectId());
assertEquals(new File(db.getWorkTree(), path), gen.getDirectory());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BasePackConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BasePackConnectionTest.java
new file mode 100644
index 0000000000..64b16f659a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BasePackConnectionTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2020, Lee Worrall 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.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.junit.Test;
+
+public class BasePackConnectionTest {
+
+ @Test
+ public void testExtractSymRefsFromCapabilities() {
+ final Map<String, String> symRefs = BasePackConnection
+ .extractSymRefsFromCapabilities(
+ Arrays.asList("symref=HEAD:refs/heads/main",
+ "symref=refs/heads/sym:refs/heads/other"));
+
+ assertEquals(2, symRefs.size());
+ assertEquals("refs/heads/main", symRefs.get("HEAD"));
+ assertEquals("refs/heads/other", symRefs.get("refs/heads/sym"));
+ }
+
+ @Test
+ public void testUpdateWithSymRefsAdds() {
+ final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
+ "refs/heads/main", ObjectId.fromString(
+ "0000000000000000000000000000000000000001"));
+
+ final Map<String, Ref> refMap = new HashMap<>();
+ refMap.put(mainRef.getName(), mainRef);
+ refMap.put("refs/heads/other",
+ new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
+ ObjectId.fromString(
+ "0000000000000000000000000000000000000002")));
+
+ final Map<String, String> symRefs = new HashMap<>();
+ symRefs.put("HEAD", "refs/heads/main");
+
+ BasePackConnection.updateWithSymRefs(refMap, symRefs);
+
+ assertThat(refMap, hasKey("HEAD"));
+ final Ref headRef = refMap.get("HEAD");
+ assertThat(headRef, instanceOf(SymbolicRef.class));
+ final SymbolicRef headSymRef = (SymbolicRef) headRef;
+ assertEquals("HEAD", headSymRef.getName());
+ assertSame(mainRef, headSymRef.getTarget());
+ }
+
+ @Test
+ public void testUpdateWithSymRefsReplaces() {
+ final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
+ "refs/heads/main", ObjectId.fromString(
+ "0000000000000000000000000000000000000001"));
+
+ final Map<String, Ref> refMap = new HashMap<>();
+ refMap.put(mainRef.getName(), mainRef);
+ refMap.put("HEAD", new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "HEAD",
+ mainRef.getObjectId()));
+ refMap.put("refs/heads/other",
+ new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
+ ObjectId.fromString(
+ "0000000000000000000000000000000000000002")));
+
+ final Map<String, String> symRefs = new HashMap<>();
+ symRefs.put("HEAD", "refs/heads/main");
+
+ BasePackConnection.updateWithSymRefs(refMap, symRefs);
+
+ assertThat(refMap, hasKey("HEAD"));
+ final Ref headRef = refMap.get("HEAD");
+ assertThat(headRef, instanceOf(SymbolicRef.class));
+ final SymbolicRef headSymRef = (SymbolicRef) headRef;
+ assertEquals("HEAD", headSymRef.getName());
+ assertSame(mainRef, headSymRef.getTarget());
+ }
+
+ @Test
+ public void testUpdateWithSymRefsWithIndirectsAdds() {
+ final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
+ "refs/heads/main", ObjectId.fromString(
+ "0000000000000000000000000000000000000001"));
+
+ final Map<String, Ref> refMap = new HashMap<>();
+ refMap.put(mainRef.getName(), mainRef);
+ refMap.put("refs/heads/other",
+ new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
+ ObjectId.fromString(
+ "0000000000000000000000000000000000000002")));
+
+ final Map<String, String> symRefs = new LinkedHashMap<>(); // Ordered
+ symRefs.put("refs/heads/sym3", "refs/heads/sym2"); // Forward reference
+ symRefs.put("refs/heads/sym1", "refs/heads/main");
+ symRefs.put("refs/heads/sym2", "refs/heads/sym1"); // Backward reference
+
+ BasePackConnection.updateWithSymRefs(refMap, symRefs);
+
+ assertThat(refMap, hasKey("refs/heads/sym1"));
+ final Ref sym1Ref = refMap.get("refs/heads/sym1");
+ assertThat(sym1Ref, instanceOf(SymbolicRef.class));
+ final SymbolicRef sym1SymRef = (SymbolicRef) sym1Ref;
+ assertEquals("refs/heads/sym1", sym1SymRef.getName());
+ assertSame(mainRef, sym1SymRef.getTarget());
+
+ assertThat(refMap, hasKey("refs/heads/sym2"));
+ final Ref sym2Ref = refMap.get("refs/heads/sym2");
+ assertThat(sym2Ref, instanceOf(SymbolicRef.class));
+ final SymbolicRef sym2SymRef = (SymbolicRef) sym2Ref;
+ assertEquals("refs/heads/sym2", sym2SymRef.getName());
+ assertSame(sym1SymRef, sym2SymRef.getTarget());
+
+ assertThat(refMap, hasKey("refs/heads/sym3"));
+ final Ref sym3Ref = refMap.get("refs/heads/sym3");
+ assertThat(sym3Ref, instanceOf(SymbolicRef.class));
+ final SymbolicRef sym3SymRef = (SymbolicRef) sym3Ref;
+ assertEquals("refs/heads/sym3", sym3SymRef.getName());
+ assertSame(sym2SymRef, sym3SymRef.getTarget());
+ }
+
+ @Test
+ public void testUpdateWithSymRefsWithIndirectsReplaces() {
+ final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
+ "refs/heads/main", ObjectId.fromString(
+ "0000000000000000000000000000000000000001"));
+
+ final Map<String, Ref> refMap = new HashMap<>();
+ refMap.put(mainRef.getName(), mainRef);
+ refMap.put("refs/heads/sym1", new ObjectIdRef.Unpeeled(
+ Ref.Storage.LOOSE, "refs/heads/sym1", mainRef.getObjectId()));
+ refMap.put("refs/heads/sym2", new ObjectIdRef.Unpeeled(
+ Ref.Storage.LOOSE, "refs/heads/sym2", mainRef.getObjectId()));
+ refMap.put("refs/heads/sym3", new ObjectIdRef.Unpeeled(
+ Ref.Storage.LOOSE, "refs/heads/sym3", mainRef.getObjectId()));
+ refMap.put("refs/heads/other",
+ new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
+ ObjectId.fromString(
+ "0000000000000000000000000000000000000002")));
+
+ final Map<String, String> symRefs = new LinkedHashMap<>(); // Ordered
+ symRefs.put("refs/heads/sym3", "refs/heads/sym2"); // Forward reference
+ symRefs.put("refs/heads/sym1", "refs/heads/main");
+ symRefs.put("refs/heads/sym2", "refs/heads/sym1"); // Backward reference
+
+ BasePackConnection.updateWithSymRefs(refMap, symRefs);
+
+ assertThat(refMap, hasKey("refs/heads/sym1"));
+ final Ref sym1Ref = refMap.get("refs/heads/sym1");
+ assertThat(sym1Ref, instanceOf(SymbolicRef.class));
+ final SymbolicRef sym1SymRef = (SymbolicRef) sym1Ref;
+ assertEquals("refs/heads/sym1", sym1SymRef.getName());
+ assertSame(mainRef, sym1SymRef.getTarget());
+
+ assertThat(refMap, hasKey("refs/heads/sym2"));
+ final Ref sym2Ref = refMap.get("refs/heads/sym2");
+ assertThat(sym2Ref, instanceOf(SymbolicRef.class));
+ final SymbolicRef sym2SymRef = (SymbolicRef) sym2Ref;
+ assertEquals("refs/heads/sym2", sym2SymRef.getName());
+ assertSame(sym1SymRef, sym2SymRef.getTarget());
+
+ assertThat(refMap, hasKey("refs/heads/sym3"));
+ final Ref sym3Ref = refMap.get("refs/heads/sym3");
+ assertThat(sym3Ref, instanceOf(SymbolicRef.class));
+ final SymbolicRef sym3SymRef = (SymbolicRef) sym3Ref;
+ assertEquals("refs/heads/sym3", sym3SymRef.getName());
+ assertSame(sym2SymRef, sym3SymRef.getTarget());
+ }
+
+ @Test
+ public void testUpdateWithSymRefsIgnoresSelfReference() {
+ final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
+ "refs/heads/main", ObjectId.fromString(
+ "0000000000000000000000000000000000000001"));
+
+ final Map<String, Ref> refMap = new HashMap<>();
+ refMap.put(mainRef.getName(), mainRef);
+ refMap.put("refs/heads/other",
+ new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
+ ObjectId.fromString(
+ "0000000000000000000000000000000000000002")));
+
+ final Map<String, String> symRefs = new LinkedHashMap<>();
+ symRefs.put("refs/heads/sym1", "refs/heads/sym1");
+
+ BasePackConnection.updateWithSymRefs(refMap, symRefs);
+
+ assertEquals(2, refMap.size());
+ assertThat(refMap, not(hasKey("refs/heads/sym1")));
+ }
+
+ @Test
+ public void testUpdateWithSymRefsIgnoreCircularReference() {
+ final Ref mainRef = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE,
+ "refs/heads/main", ObjectId.fromString(
+ "0000000000000000000000000000000000000001"));
+
+ final Map<String, Ref> refMap = new HashMap<>();
+ refMap.put(mainRef.getName(), mainRef);
+ refMap.put("refs/heads/other",
+ new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/other",
+ ObjectId.fromString(
+ "0000000000000000000000000000000000000002")));
+
+ final Map<String, String> symRefs = new LinkedHashMap<>();
+ symRefs.put("refs/heads/sym2", "refs/heads/sym1");
+ symRefs.put("refs/heads/sym1", "refs/heads/sym2");
+
+ BasePackConnection.updateWithSymRefs(refMap, symRefs);
+
+ assertEquals(2, refMap.size());
+ assertThat(refMap, not(hasKey("refs/heads/sym1")));
+ assertThat(refMap, not(hasKey("refs/heads/sym2")));
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java
index fcbec52a54..5336dd73c6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpConfigTest.java
@@ -13,7 +13,9 @@ package org.eclipse.jgit.transport;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.util.SystemReader;
import org.junit.Before;
import org.junit.Test;
@@ -25,6 +27,7 @@ public class HttpConfigTest {
private static final String DEFAULT = "[http]\n" + "\tpostBuffer = 1\n"
+ "\tsslVerify= true\n" + "\tfollowRedirects = true\n"
+ + "\textraHeader = x: y\n" + "\tuserAgent = Test/0.1\n"
+ "\tmaxRedirects = 5\n\n";
private Config config;
@@ -95,7 +98,8 @@ public class HttpConfigTest {
@Test
public void testMatchWithInvalidUriInConfig() throws Exception {
config.fromText(
- DEFAULT + "[http \"///\"]\n" + "\tpostBuffer = 1024\n");
+ DEFAULT + "[http \"///#expectedWarning\"]\n"
+ + "\tpostBuffer = 1024\n");
HttpConfig http = new HttpConfig(config,
new URIish("http://example.com/path/repo.git"));
assertEquals(1, http.getPostBuffer());
@@ -103,7 +107,8 @@ public class HttpConfigTest {
@Test
public void testMatchWithInvalidAndValidUriInConfig() throws Exception {
- config.fromText(DEFAULT + "[http \"///\"]\n" + "\tpostBuffer = 1024\n"
+ config.fromText(DEFAULT + "[http \"///#expectedWarning\"]\n"
+ + "\tpostBuffer = 1024\n"
+ "[http \"http://example.com\"]\n" + "\tpostBuffer = 2048\n");
HttpConfig http = new HttpConfig(config,
new URIish("http://example.com/path/repo.git"));
@@ -174,4 +179,93 @@ public class HttpConfigTest {
new URIish("http://user@example.com/path"));
assertEquals(1024, http.getPostBuffer());
}
+
+ @Test
+ public void testExtraHeaders() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\textraHeader=foo: bar\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertEquals(1, http.getExtraHeaders().size());
+ assertEquals("foo: bar", http.getExtraHeaders().get(0));
+ }
+
+ @Test
+ public void testExtraHeadersMultiple() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\textraHeader=foo: bar\n" //
+ + "\textraHeader=bar: foo\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertEquals(2, http.getExtraHeaders().size());
+ assertEquals("foo: bar", http.getExtraHeaders().get(0));
+ assertEquals("bar: foo", http.getExtraHeaders().get(1));
+ }
+
+ @Test
+ public void testExtraHeadersReset() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\textraHeader=foo: bar\n" //
+ + "\textraHeader=bar: foo\n" //
+ + "\textraHeader=\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertTrue(http.getExtraHeaders().isEmpty());
+ }
+
+ @Test
+ public void testExtraHeadersResetAndMore() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\textraHeader=foo: bar\n" //
+ + "\textraHeader=bar: foo\n" //
+ + "\textraHeader=\n" //
+ + "\textraHeader=baz: something\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertEquals(1, http.getExtraHeaders().size());
+ assertEquals("baz: something", http.getExtraHeaders().get(0));
+ }
+
+ @Test
+ public void testUserAgent() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\tuserAgent=DummyAgent/4.0\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertEquals("DummyAgent/4.0", http.getUserAgent());
+ }
+
+ @Test
+ public void testUserAgentEnvOverride() throws Exception {
+ String mockAgent = "jgit-test/5.10.0";
+ SystemReader originalReader = SystemReader.getInstance();
+ SystemReader.setInstance(new MockSystemReader() {
+
+ @Override
+ public String getenv(String variable) {
+ if ("GIT_HTTP_USER_AGENT".equals(variable)) {
+ return mockAgent;
+ }
+ return super.getenv(variable);
+ }
+ });
+ try {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\tuserAgent=DummyAgent/4.0\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertEquals(mockAgent, http.getUserAgent());
+ } finally {
+ SystemReader.setInstance(originalReader);
+ }
+ }
+
+ @Test
+ public void testUserAgentNonAscii() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\tuserAgent= d ümmy Agent -5.10\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/"));
+ assertEquals("d.mmy.Agent.-5.10", http.getUserAgent());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java
index 965a2faf8e..c0db83a820 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java
@@ -9,6 +9,10 @@
*/
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
import static org.eclipse.jgit.transport.ObjectIdMatcher.hasOnlyObjectIds;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -160,6 +164,10 @@ public class ProtocolV0ParserTest {
assertThat(request.getWantIds(),
hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e",
"f900c8326a43303685c46b279b9f70411bff1a4b"));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_BLOB));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
assertEquals(13000, request.getFilterSpec().getBlobLimit());
assertEquals(-1, request.getFilterSpec().getTreeDepthLimit());
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java
index 038ce717b3..837bdce919 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java
@@ -9,6 +9,10 @@
*/
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
import static org.eclipse.jgit.transport.ObjectIdMatcher.hasOnlyObjectIds;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
@@ -195,7 +199,11 @@ public class ProtocolV2ParserTest {
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
- assertEquals(0, request.getFilterSpec().getBlobLimit());
+ assertFalse(request.getFilterSpec().allowsType(OBJ_BLOB));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
+ assertEquals(-1, request.getFilterSpec().getBlobLimit());
assertEquals(-1, request.getFilterSpec().getTreeDepthLimit());
}
@@ -207,6 +215,10 @@ public class ProtocolV2ParserTest {
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
+ assertTrue(request.getFilterSpec().allowsType(OBJ_BLOB));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
assertEquals(15, request.getFilterSpec().getBlobLimit());
assertEquals(-1, request.getFilterSpec().getTreeDepthLimit());
}
@@ -219,6 +231,10 @@ public class ProtocolV2ParserTest {
ProtocolV2Parser parser = new ProtocolV2Parser(
ConfigBuilder.start().allowFilter().done());
FetchV2Request request = parser.parseFetchRequest(pckIn);
+ assertTrue(request.getFilterSpec().allowsType(OBJ_BLOB));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TREE));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_COMMIT));
+ assertTrue(request.getFilterSpec().allowsType(OBJ_TAG));
assertEquals(-1, request.getFilterSpec().getBlobLimit());
assertEquals(3, request.getFilterSpec().getTreeDepthLimit());
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
index 0179d8c26f..21fde3e76e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
@@ -162,7 +162,9 @@ public class PushConnectionTest {
fail("server did not abort");
} catch (TransportException e) {
String msg = e.getMessage();
- assertEquals("remote: Too many commands", msg);
+ assertEquals(
+ "remote: Commands size exceeds limit defined in receive.maxCommandBytes",
+ msg);
}
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java
index b84b6b2e0b..029b45e1e6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportHttpTest.java
@@ -18,7 +18,9 @@ import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
+import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.internal.transport.http.NetscapeCookieFile;
@@ -155,4 +157,50 @@ public class TransportHttpTest extends SampleDataRepositoryTestCase {
cookieFile.exists());
}
}
+
+ private void assertHeaders(String expected, String... headersToAdd) {
+ HttpConnection fake = Mockito.mock(HttpConnection.class);
+ Map<String, String> headers = new LinkedHashMap<>();
+ Mockito.doAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ headers.put(args[0].toString(), args[1].toString());
+ return null;
+ }).when(fake).setRequestProperty(ArgumentMatchers.anyString(),
+ ArgumentMatchers.anyString());
+ TransportHttp.addHeaders(fake, Arrays.asList(headersToAdd));
+ Assert.assertEquals(expected, headers.toString());
+ }
+
+ @Test
+ public void testAddHeaders() {
+ assertHeaders("{a=b, c=d}", "a: b", "c :d");
+ }
+
+ @Test
+ public void testAddHeaderEmptyValue() {
+ assertHeaders("{a-x=b, c=, d=e}", "a-x: b", "c:", "d:e");
+ }
+
+ @Test
+ public void testSkipHeaderWithEmptyKey() {
+ assertHeaders("{a=b, c=d}", "a: b", " : x", "c :d");
+ assertHeaders("{a=b, c=d}", "a: b", ": x", "c :d");
+ }
+
+ @Test
+ public void testSkipHeaderWithoutKey() {
+ assertHeaders("{a=b, c=d}", "a: b", "x", "c :d");
+ }
+
+ @Test
+ public void testSkipHeaderWithInvalidKey() {
+ assertHeaders("{a=b, c=d}", "a: b", "q/p: x", "c :d");
+ assertHeaders("{a=b, c=d}", "a: b", "ä: x", "c :d");
+ }
+
+ @Test
+ public void testSkipHeaderWithNonAsciiValue() {
+ assertHeaders("{a=b, c=d}", "a: b", "q/p: x", "c :d");
+ assertHeaders("{a=b, c=d}", "a: b", "x: ä", "c :d");
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index d58e576984..ce546e357e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -127,7 +127,7 @@ public class UploadPackTest {
}
@Test
- public void testFetchWithBlobNoneFilter() throws Exception {
+ public void testFetchWithBlobZeroFilter() throws Exception {
InMemoryRepository server2 = newRepo("server2");
try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
server2)) {
@@ -298,6 +298,38 @@ public class UploadPackTest {
}
@Test
+ public void testFetchWithTreeZeroFilter() throws Exception {
+ InMemoryRepository server2 = newRepo("server2");
+ try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
+ server2)) {
+ RevBlob blob1 = remote2.blob("foobar");
+ RevBlob blob2 = remote2.blob("fooba");
+ RevTree tree = remote2.tree(remote2.file("1", blob1),
+ remote2.file("2", blob2));
+ RevCommit commit = remote2.commit(tree);
+ remote2.update("master", commit);
+
+ server2.getConfig().setBoolean("uploadpack", null, "allowfilter",
+ true);
+
+ testProtocol = new TestProtocol<>((Object req, Repository db) -> {
+ UploadPack up = new UploadPack(db);
+ return up;
+ }, null);
+ uri = testProtocol.register(ctx, server2);
+
+ try (Transport tn = testProtocol.open(uri, client, "server2")) {
+ tn.setFilterSpec(FilterSpec.withTreeDepthLimit(0));
+ tn.fetch(NullProgressMonitor.INSTANCE,
+ Collections.singletonList(new RefSpec(commit.name())));
+ assertFalse(client.getObjectDatabase().has(tree.toObjectId()));
+ assertFalse(client.getObjectDatabase().has(blob1.toObjectId()));
+ assertFalse(client.getObjectDatabase().has(blob2.toObjectId()));
+ }
+ }
+ }
+
+ @Test
public void testFetchWithNonSupportingServer() throws Exception {
InMemoryRepository server2 = newRepo("server2");
try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>(
@@ -329,21 +361,21 @@ public class UploadPackTest {
}
/*
- * Invokes UploadPack with protocol v2 and sends it the given lines,
+ * Invokes UploadPack with specified protocol version and sends it the given lines,
* and returns UploadPack's output stream.
*/
- private ByteArrayInputStream uploadPackV2Setup(
+ private ByteArrayInputStream uploadPackSetup(String version,
Consumer<UploadPack> postConstructionSetup, String... inputLines)
throws Exception {
ByteArrayInputStream send = linesAsInputStream(inputLines);
- server.getConfig().setString("protocol", null, "version", "2");
+ server.getConfig().setString("protocol", null, "version", version);
UploadPack up = new UploadPack(server);
if (postConstructionSetup != null) {
postConstructionSetup.accept(up);
}
- up.setExtraParameters(Sets.of("version=2"));
+ up.setExtraParameters(Sets.of("version=".concat(version)));
ByteArrayOutputStream recv = new ByteArrayOutputStream();
up.upload(send, recv, null);
@@ -371,6 +403,30 @@ public class UploadPackTest {
}
/*
+ * Invokes UploadPack with protocol v1 and sends it the given lines.
+ * Returns UploadPack's output stream, not including the capability
+ * advertisement by the server.
+ */
+ private ByteArrayInputStream uploadPackV1(
+ Consumer<UploadPack> postConstructionSetup,
+ String... inputLines)
+ throws Exception {
+ ByteArrayInputStream recvStream =
+ uploadPackSetup("1", postConstructionSetup, inputLines);
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ // drain capabilities
+ while (!PacketLineIn.isEnd(pckIn.readString())) {
+ // do nothing
+ }
+ return recvStream;
+ }
+
+ private ByteArrayInputStream uploadPackV1(String... inputLines) throws Exception {
+ return uploadPackV1(null, inputLines);
+ }
+
+ /*
* Invokes UploadPack with protocol v2 and sends it the given lines.
* Returns UploadPack's output stream, not including the capability
* advertisement by the server.
@@ -380,7 +436,7 @@ public class UploadPackTest {
String... inputLines)
throws Exception {
ByteArrayInputStream recvStream =
- uploadPackV2Setup(postConstructionSetup, inputLines);
+ uploadPackSetup("2", postConstructionSetup, inputLines);
PacketLineIn pckIn = new PacketLineIn(recvStream);
// drain capabilities
@@ -420,7 +476,7 @@ public class UploadPackTest {
@Test
public void testV2Capabilities() throws Exception {
TestV2Hook hook = new TestV2Hook();
- ByteArrayInputStream recvStream = uploadPackV2Setup(
+ ByteArrayInputStream recvStream = uploadPackSetup( "2",
(UploadPack up) -> {up.setProtocolV2Hook(hook);},
PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
@@ -443,7 +499,7 @@ public class UploadPackTest {
String fetchCapability) throws Exception {
server.getConfig().setBoolean(configSection, null, configName, true);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, PacketLineIn.end());
+ uploadPackSetup("2", null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
@@ -467,7 +523,7 @@ public class UploadPackTest {
String configName, String fetchCapability) throws Exception {
server.getConfig().setBoolean(configSection, null, configName, false);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, PacketLineIn.end());
+ uploadPackSetup("2", null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
@@ -519,7 +575,7 @@ public class UploadPackTest {
server.getConfig().setBoolean("uploadpack", null, "allowrefinwant", true);
server.getConfig().setBoolean("uploadpack", null, "advertiserefinwant", false);
ByteArrayInputStream recvStream =
- uploadPackV2Setup(null, PacketLineIn.end());
+ uploadPackSetup("2", null, PacketLineIn.end());
PacketLineIn pckIn = new PacketLineIn(recvStream);
assertThat(pckIn.readString(), is("version 2"));
@@ -683,7 +739,7 @@ public class UploadPackTest {
PacketLineIn.end() };
TestV2Hook testHook = new TestV2Hook();
- uploadPackV2Setup((UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
+ uploadPackSetup("2", (UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
LsRefsV2Request req = testHook.lsRefsRequest;
assertEquals(2, req.getServerOptions().size());
@@ -1028,6 +1084,70 @@ public class UploadPackTest {
}
@Test
+ public void testUploadNewBytes() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwx";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+ remote.update("branch1", child);
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + child.toObjectId().getName() + "\n",
+ "ofs-delta\n",
+ "done\n",
+ PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+ assertThat(pckIn.readString(), is("packfile"));
+ ReceivedPackStatistics receivedStats = parsePack(recvStream);
+ assertTrue(receivedStats.getNumBytesDuplicated() == 0);
+ assertTrue(receivedStats.getNumObjectsDuplicated() == 0);
+ }
+
+ @Test
+ public void testUploadRedundantBytes() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+ remote.update("branch1", child);
+
+ try (TestRepository<InMemoryRepository> local = new TestRepository<>(
+ client)) {
+ RevBlob localParentBlob = local.blob(commonInBlob + "a");
+ RevCommit localParent = local
+ .commit(local.tree(local.file("foo", localParentBlob)));
+ RevBlob localChildBlob = local.blob(commonInBlob + "b");
+ RevCommit localChild = local.commit(
+ local.tree(local.file("foo", localChildBlob)), localParent);
+ local.update("branch1", localChild);
+ }
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + child.toObjectId().getName() + "\n",
+ "ofs-delta\n",
+ "done\n",
+ PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+ assertThat(pckIn.readString(), is("packfile"));
+ ReceivedPackStatistics receivedStats = parsePack(recvStream);
+
+ long sizeOfHeader = 12;
+ long sizeOfTrailer = 20;
+ long expectedSize = receivedStats.getNumBytesRead() - sizeOfHeader
+ - sizeOfTrailer;
+ assertTrue(receivedStats.getNumBytesDuplicated() == expectedSize);
+ assertTrue(receivedStats.getNumObjectsDuplicated() == 6);
+ }
+
+ @Test
public void testV2FetchOfsDelta() throws Exception {
String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
@@ -1439,7 +1559,7 @@ public class UploadPackTest {
PacketLineIn.end() };
TestV2Hook testHook = new TestV2Hook();
- uploadPackV2Setup((UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
+ uploadPackSetup("2", (UploadPack up) -> {up.setProtocolV2Hook(testHook);}, lines);
FetchV2Request req = testHook.fetchRequest;
assertNotNull(req);
@@ -2292,6 +2412,93 @@ public class UploadPackTest {
assertEquals(1, ((RefCallsCountingRepository)server).numRefCalls());
}
+ @Test
+ public void testNotAdvertisedWantsV1Fetch() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote
+ .commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote
+ .commit(remote.tree(remote.file("foo", childBlob)), parent);
+ remote.update("branch1", child);
+
+ uploadPackV1("want " + child.toObjectId().getName() + "\n",
+ PacketLineIn.end(),
+ "have " + parent.toObjectId().getName() + "\n",
+ "done\n", PacketLineIn.end());
+
+ assertEquals(0, stats.getNotAdvertisedWants());
+ }
+
+ @Test
+ public void testNotAdvertisedWantsV1FetchRequestPolicyReachableCommit() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote
+ .commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote
+ .commit(remote.tree(remote.file("foo", childBlob)), parent);
+
+ remote.update("branch1", child);
+
+ uploadPackV1((UploadPack up) -> {up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);},
+ "want " + parent.toObjectId().getName() + "\n",
+ PacketLineIn.end(),
+ "done\n", PacketLineIn.end());
+
+ assertEquals(1, stats.getNotAdvertisedWants());
+ }
+
+ @Test
+ public void testNotAdvertisedWantsV2FetchThinPack() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote
+ .commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote
+ .commit(remote.tree(remote.file("foo", childBlob)), parent);
+ remote.update("branch1", child);
+
+ ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + child.toObjectId().getName() + "\n",
+ "have " + parent.toObjectId().getName() + "\n", "thin-pack\n",
+ "done\n", PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ assertThat(pckIn.readString(), is("packfile"));
+
+ assertEquals(0, stats.getNotAdvertisedWants());
+ }
+
+ @Test
+ public void testNotAdvertisedWantsV2FetchRequestPolicyReachableCommit() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote
+ .commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote
+ .commit(remote.tree(remote.file("foo", childBlob)), parent);
+
+ remote.update("branch1", child);
+
+ uploadPackV2((UploadPack up) -> {up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT);},
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + parent.toObjectId().getName() + "\n", "thin-pack\n",
+ "done\n", PacketLineIn.end());
+
+ assertEquals(1, stats.getNotAdvertisedWants());
+ }
+
private class RefCallsCountingRepository extends InMemoryRepository {
private final InMemoryRepository.MemRefDatabase refdb;
private int numRefCalls;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java
index fb90461e1a..c391694fbc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFInputStreamTest.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010, Marc Strapetz <marc.strapetz@syntevo.com>
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> and others
+ * Copyright (C) 2015, 2020 Ivan Motsch <ivan.motsch@bsiag.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -17,7 +17,9 @@ import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.function.Function;
+import org.eclipse.jgit.util.io.AutoLFInputStream.StreamFlag;
import org.junit.Test;
public class AutoLFInputStreamTest {
@@ -25,47 +27,65 @@ public class AutoLFInputStreamTest {
@Test
public void testLF() throws IOException {
final byte[] bytes = asBytes("1\n2\n3");
- test(bytes, bytes, false);
+ test(bytes, bytes);
}
@Test
public void testCR() throws IOException {
final byte[] bytes = asBytes("1\r2\r3");
- test(bytes, bytes, false);
+ test(bytes, bytes);
}
@Test
public void testCRLF() throws IOException {
- test(asBytes("1\r\n2\r\n3"), asBytes("1\n2\n3"), false);
+ test(asBytes("1\r\n2\r\n3"), asBytes("1\n2\n3"));
}
@Test
public void testLFCR() throws IOException {
final byte[] bytes = asBytes("1\n\r2\n\r3");
- test(bytes, bytes, false);
+ test(bytes, bytes);
}
@Test
public void testEmpty() throws IOException {
final byte[] bytes = asBytes("");
- test(bytes, bytes, false);
+ test(bytes, bytes);
}
@Test
public void testBinaryDetect() throws IOException {
final byte[] bytes = asBytes("1\r\n2\r\n3\0");
- test(bytes, bytes, true);
+ test(bytes, bytes, StreamFlag.DETECT_BINARY);
}
@Test
public void testBinaryDontDetect() throws IOException {
- test(asBytes("1\r\n2\r\n3\0"), asBytes("1\n2\n3\0"), false);
+ test(asBytes("1\r\n2\r\n3\0"), asBytes("1\n2\n3\0"));
+ }
+
+ @Test
+ public void testCrLf() throws IOException {
+ byte[] bytes = asBytes("1\r\n2\n3\r\n\r");
+ test(bytes, bytes, in -> AutoLFInputStream.create(in,
+ StreamFlag.DETECT_BINARY, StreamFlag.FOR_CHECKOUT));
+ }
+
+ @Test
+ public void testCrLfDontDetect() throws IOException {
+ test(asBytes("1\r\n2\r\n"), asBytes("1\n2\n"),
+ in -> AutoLFInputStream.create(in, StreamFlag.DETECT_BINARY));
+ }
+
+ private static void test(byte[] input, byte[] expected, StreamFlag... flags)
+ throws IOException {
+ test(input, expected, in -> AutoLFInputStream.create(in, flags));
}
private static void test(byte[] input, byte[] expected,
- boolean detectBinary) throws IOException {
+ Function<InputStream, InputStream> factory) throws IOException {
try (InputStream bis1 = new ByteArrayInputStream(input);
- InputStream cis1 = new AutoLFInputStream(bis1, detectBinary)) {
+ InputStream cis1 = factory.apply(bis1)) {
int index1 = 0;
for (int b = cis1.read(); b != -1; b = cis1.read()) {
assertEquals(expected[index1], (byte) b);
@@ -77,8 +97,7 @@ public class AutoLFInputStreamTest {
for (int bufferSize = 1; bufferSize < 10; bufferSize++) {
final byte[] buffer = new byte[bufferSize];
try (InputStream bis2 = new ByteArrayInputStream(input);
- InputStream cis2 = new AutoLFInputStream(bis2,
- detectBinary)) {
+ InputStream cis2 = factory.apply(bis2)) {
int read = 0;
for (int readNow = cis2.read(buffer, 0,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFOutputStreamTest.java
new file mode 100644
index 0000000000..1b7e55e457
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoLFOutputStreamTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020, 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.util.io;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertArrayEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.junit.Test;
+
+public class AutoLFOutputStreamTest {
+
+ @Test
+ public void testLF() throws IOException {
+ final byte[] bytes = asBytes("1\n2\n3");
+ test(bytes, bytes, false);
+ }
+
+ @Test
+ public void testCR() throws IOException {
+ final byte[] bytes = asBytes("1\r2\r3");
+ test(bytes, bytes, false);
+ }
+
+ @Test
+ public void testCRLFNoDetect() throws IOException {
+ test(asBytes("1\r\n2\r\n3"), asBytes("1\n2\n3"), false);
+ }
+
+ @Test
+ public void testLFCR() throws IOException {
+ final byte[] bytes = asBytes("1\n\r2\n\r3");
+ test(bytes, bytes, false);
+ }
+
+ @Test
+ public void testEmpty() throws IOException {
+ final byte[] bytes = asBytes("");
+ test(bytes, bytes, false);
+ }
+
+ @Test
+ public void testBinaryDetect() throws IOException {
+ final byte[] bytes = asBytes("1\r\n2\r\n3\0");
+ test(bytes, bytes, true);
+ }
+
+ @Test
+ public void testBinaryDontDetect() throws IOException {
+ test(asBytes("1\r\n2\r\n3\0"), asBytes("1\n2\n3\0"), false);
+ }
+
+ @Test
+ public void testCrLfDetect() throws IOException {
+ byte[] bytes = asBytes("1\r\n2\n3\r\n\r");
+ test(bytes, bytes, true);
+ }
+
+ private static void test(byte[] input, byte[] expected,
+ boolean detectBinary) throws IOException {
+ try (ByteArrayOutputStream result = new ByteArrayOutputStream();
+ OutputStream out = new AutoLFOutputStream(result,
+ detectBinary)) {
+ out.write(input);
+ out.close();
+ assertArrayEquals(expected, result.toByteArray());
+ }
+ }
+
+ private static byte[] asBytes(String in) {
+ return in.getBytes(UTF_8);
+ }
+}
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
new file mode 100644
index 0000000000..538c6f7bfb
--- /dev/null
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jgit" version="2">
+ <resource path="src/org/eclipse/jgit/lib/TypedConfigGetter.java" type="org.eclipse.jgit.lib.TypedConfigGetter">
+ <filter id="404000815">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/>
+ <message_argument value="getPath(Config, String, String, String, FS, File, Path)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/storage/pack/PackStatistics.java" type="org.eclipse.jgit.storage.pack.PackStatistics$Accumulator">
+ <filter id="336658481">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.storage.pack.PackStatistics.Accumulator"/>
+ <message_argument value="notAdvertisedWants"/>
+ </message_arguments>
+ </filter>
+ <filter id="336658481">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.storage.pack.PackStatistics.Accumulator"/>
+ <message_argument value="reachabilityCheckDuration"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/transport/HttpConfig.java" type="org.eclipse.jgit.transport.HttpConfig">
+ <filter id="336658481">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.transport.HttpConfig"/>
+ <message_argument value="EXTRA_HEADER"/>
+ </message_arguments>
+ </filter>
+ <filter id="336658481">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.transport.HttpConfig"/>
+ <message_argument value="USER_AGENT"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD
index f7970976b0..2083372248 100644
--- a/org.eclipse.jgit/BUILD
+++ b/org.eclipse.jgit/BUILD
@@ -14,7 +14,7 @@ SRCS = glob(
RESOURCES = glob(["resources/**"])
java_library(
- name = "jgit",
+ name = "jgit_non_stamped",
srcs = SRCS,
resource_strip_prefix = "org.eclipse.jgit/resources",
resources = RESOURCES,
@@ -25,6 +25,27 @@ java_library(
],
)
+genrule(
+ name = "jgit",
+ srcs = [":jgit_non_stamped"],
+ outs = ["jgit.jar"],
+ cmd = " && ".join([
+ "ROOT=$$PWD",
+ "TMP=$$(mktemp -d || mktemp -d -t bazel-tmp)",
+ "TZ=UTC",
+ "export TZ",
+ "GEN_VERSION=$$(cat bazel-out/stable-status.txt | grep -w STABLE_BUILD_JGIT_LABEL | cut -d ' ' -f 2)",
+ "cd $$TMP",
+ "unzip -q $$ROOT/$<",
+ "echo \"Implementation-Version: $$GEN_VERSION\n$$(cat META-INF/MANIFEST.MF)\" > META-INF/MANIFEST.MF",
+ "find . -exec touch '{}' ';'",
+ "zip -Xqr $$ROOT/$@ .",
+ "rm -rf $$TMP",
+ ]),
+ stamp = 1,
+ visibility = ["//visibility:public"],
+)
+
java_library(
name = "insecure_cipher_factory",
srcs = INSECURE_CIPHER_FACTORY,
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 52aa8a353f..403b8eed0f 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -135,6 +135,7 @@ Export-Package: org.eclipse.jgit.annotations;version="6.0.0",
org.eclipse.jgit.util.time",
org.eclipse.jgit.lib.internal;version="6.0.0";
x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.logging;version="6.0.0",
org.eclipse.jgit.merge;version="6.0.0";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
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 e6da551bb7..12902b9004 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -202,10 +202,8 @@ countingObjects=Counting objects
corruptPack=Pack file {0} is corrupt, removing it from pack list
createBranchFailedUnknownReason=Create branch failed for unknown reason
createBranchUnexpectedResult=Create branch returned unexpected result {0}
-createJGitConfigFailed=Creating JGit config directory {} failed
createNewFileFailed=Could not create new file {0}
createRequiresZeroOldId=Create requires old ID to be zero
-createXDGConfigHomeFailed=Creating XDG_CONFIG_HOME directory {} failed
credentialPassword=Password
credentialPassphrase=Passphrase
credentialUsername=Username
@@ -215,6 +213,7 @@ deepenNotWithDeepen=Cannot combine deepen with deepen-not
deepenSinceWithDeepen=Cannot combine deepen with deepen-since
deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
deleteFileFailed=Could not delete file {0}
+deletedOrphanInPackDir=Deleted orphaned file {}
deleteRequiresZeroNewId=Delete requires new ID to be zero
deleteTagUnexpectedResult=Delete tag returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported.
@@ -224,6 +223,8 @@ dirCacheDoesNotHaveABackingFile=DirCache does not have a backing file
dirCacheFileIsNotLocked=DirCache {0} not locked
dirCacheIsNotLocked=DirCache is not locked
DIRCChecksumMismatch=DIRC checksum mismatch
+DIRCCorruptLength=DIRC variable int {0} invalid after entry for {1}
+DIRCCorruptLengthFirst=DIRC variable int {0} invalid in first entry
DIRCExtensionIsTooLargeAt=DIRC extension {0} is too large at {1} bytes.
DIRCExtensionNotSupportedByThisVersion=DIRC extension {0} not supported by this version.
DIRCHasTooManyEntries=DIRC has too many entries.
@@ -347,6 +348,9 @@ invalidFilter=Invalid filter: {0}
invalidGitdirRef = Invalid .git reference in file ''{0}''
invalidGitModules=Invalid .gitmodules file
invalidGitType=invalid git type: {0}
+invalidHeaderFormat=Invalid header from git config http.extraHeader ignored: no colon or empty key in header ''{0}''
+invalidHeaderKey=Invalid header from git config http.extraHeader ignored: key contains illegal characters; see RFC 7230: ''{0}''
+invalidHeaderValue=Invalid header from git config http.extraHeader ignored: value should be 7bit-ASCII characters only: ''{0}''
invalidHexString=Invalid hex string: {0}
invalidHomeDirectory=Invalid home directory: {0}
invalidHooksPath=Invalid git config core.hooksPath = {0}
@@ -408,6 +412,10 @@ lockError=lock error: {0}
lockFailedRetry=locking {0} failed after {1} retries
lockOnNotClosed=Lock on {0} not closed.
lockOnNotHeld=Lock on {0} not held.
+logInconsistentFiletimeDiff={}: inconsistent duration from file timestamps on {}, {}: {} > {}, but diff = {}. Aborting measurement at resolution {}.
+logLargerFiletimeDiff={}: inconsistent duration from file timestamps on {}, {}: diff = {} > {} (last good value). Aborting measurement.
+logSmallerFiletime={}: got smaller file timestamp on {}, {}: {} < {}. Aborting measurement at resolution {}.
+logXDGConfigHomeInvalid=Environment variable XDG_CONFIG_HOME contains an invalid path {}
maxCountMustBeNonNegative=max count must be >= 0
mergeConflictOnNonNoteEntries=Merge conflict on non-note entries: base = {0}, ours = {1}, theirs = {2}
mergeConflictOnNotes=Merge conflict on note {0}. base = {1}, ours = {2}, theirs = {2}
@@ -621,6 +629,7 @@ sourceRefDoesntResolveToAnyObject=Source ref {0} doesn''t resolve to any object.
sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD
sshCommandFailed=Execution of ssh command ''{0}'' failed with error ''{1}''
+sshCommandTimeout=Execution of ssh command ''{0}'' timed out after {1} seconds
sslFailureExceptionMessage=Secure connection to {0} could not be established because of SSL problems
sslFailureInfo=A secure connection to {0} could not be established because the server''s certificate could not be validated.
sslFailureCause=SSL reported: {0}
@@ -661,7 +670,7 @@ threadInterruptedWhileRunning="Current thread interrupted while running {0}"
timeIsUncertain=Time is uncertain
timerAlreadyTerminated=Timer already terminated
timeoutMeasureFsTimestampResolution=measuring filesystem timestamp resolution for ''{0}'' timed out, fall back to resolution of 2 seconds
-tooManyCommands=Too many commands
+tooManyCommands=Commands size exceeds limit defined in receive.maxCommandBytes
tooManyFilters=Too many "filter" lines in request
tooManyIncludeRecursions=Too many recursions; circular includes in config file(s)?
topologicalSortRequired=Topological sort required.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 0dc5d5e7f7..847ab0a9a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
- * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com> and others
+ * Copyright (C) 2011, 2020 Matthias Sohn <matthias.sohn@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -503,6 +503,11 @@ public class CheckoutCommand extends GitCommand<Ref> {
editor.add(new PathEdit(path) {
@Override
public void apply(DirCacheEntry ent) {
+ if (ent.getStage() != DirCacheEntry.STAGE_0) {
+ // A checkout on a conflicting file stages the checked
+ // out file and resolves the conflict.
+ ent.setStage(DirCacheEntry.STAGE_0);
+ }
ent.setObjectId(blobId);
ent.setFileMode(mode);
checkoutPath(ent, r,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index 30d7f9adc4..aba86fc361 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -413,6 +413,10 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
return null;
}
+ if (idHEAD != null && idHEAD.isSymbolic()) {
+ return idHEAD.getTarget();
+ }
+
Ref master = result.getAdvertisedRef(Constants.R_HEADS
+ Constants.MASTER);
ObjectId objectId = master != null ? master.getObjectId() : null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
index 8d427385d4..6a9fbd4f63 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -9,6 +9,7 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.R_REFS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import java.io.IOException;
@@ -73,6 +74,11 @@ public class DescribeCommand extends GitCommand<String> {
private List<FileNameMatcher> matchers = new ArrayList<>();
/**
+ * Whether to use all refs in the refs/ namespace
+ */
+ private boolean useAll;
+
+ /**
* Whether to use all tags (incl. lightweight) or not.
*/
private boolean useTags;
@@ -153,6 +159,22 @@ public class DescribeCommand extends GitCommand<String> {
}
/**
+ * Instead of using only the annotated tags, use any ref found in refs/
+ * namespace. This option enables matching any known branch,
+ * remote-tracking branch, or lightweight tag.
+ *
+ * @param all
+ * <code>true</code> enables matching any ref found in refs/
+ * like setting option --all in c git
+ * @return {@code this}
+ * @since 5.10
+ */
+ public DescribeCommand setAll(boolean all) {
+ this.useAll = all;
+ return this;
+ }
+
+ /**
* Instead of using only the annotated tags, use any tag found in refs/tags
* namespace. This option enables matching lightweight (non-annotated) tags
* or not.
@@ -186,7 +208,7 @@ public class DescribeCommand extends GitCommand<String> {
private String longDescription(Ref tag, int depth, ObjectId tip)
throws IOException {
return String.format(
- "%s-%d-g%s", tag.getName().substring(R_TAGS.length()), //$NON-NLS-1$
+ "%s-%d-g%s", formatRefName(tag.getName()), //$NON-NLS-1$
Integer.valueOf(depth), w.getObjectReader().abbreviate(tip)
.name());
}
@@ -244,8 +266,7 @@ public class DescribeCommand extends GitCommand<String> {
for (FileNameMatcher matcher : matchers) {
Stream<Ref> m = tags.stream().filter(
tag -> {
- matcher.append(
- tag.getName().substring(R_TAGS.length()));
+ matcher.append(formatRefName(tag.getName()));
boolean result = matcher.isMatch();
matcher.reset();
return result;
@@ -283,7 +304,7 @@ public class DescribeCommand extends GitCommand<String> {
}
Collection<Ref> tagList = repo.getRefDatabase()
- .getRefsByPrefix(R_TAGS);
+ .getRefsByPrefix(useAll ? R_REFS : R_TAGS);
Map<ObjectId, List<Ref>> tags = tagList.stream()
.filter(this::filterLightweightTags)
.collect(Collectors.groupingBy(this::getObjectIdFromRef));
@@ -336,7 +357,7 @@ public class DescribeCommand extends GitCommand<String> {
Optional<Ref> bestMatch = getBestMatch(tags.get(target));
if (bestMatch.isPresent()) {
return longDesc ? longDescription(bestMatch.get(), 0, target) :
- bestMatch.get().getName().substring(R_TAGS.length());
+ formatRefName(bestMatch.get().getName());
}
w.markStart(target);
@@ -408,6 +429,16 @@ public class DescribeCommand extends GitCommand<String> {
}
/**
+ * Removes the refs/ or refs/tags prefix from tag names
+ * @param name the name of the tag
+ * @return the tag name with its prefix removed
+ */
+ private String formatRefName(String name) {
+ return name.startsWith(R_TAGS) ? name.substring(R_TAGS.length()) :
+ name.substring(R_REFS.length());
+ }
+
+ /**
* Whether we use lightweight tags or not for describe Candidates
*
* @param ref
@@ -419,7 +450,7 @@ public class DescribeCommand extends GitCommand<String> {
private boolean filterLightweightTags(Ref ref) {
ObjectId id = ref.getObjectId();
try {
- return this.useTags || (id != null && (w.parseTag(id) != null));
+ return this.useAll || this.useTags || (id != null && (w.parseTag(id) != null));
} catch (IOException e) {
return false;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java
index ac17d3a642..f4b8ac2e07 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleDeinitCommand.java
@@ -20,8 +20,10 @@ import java.util.Collections;
import java.util.List;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidConfigurationException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoHeadException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.ObjectId;
@@ -119,6 +121,8 @@ public class SubmoduleDeinitCommand
}
}
return results;
+ } catch (ConfigInvalidException e) {
+ throw new InvalidConfigurationException(e.getMessage(), e);
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
}
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 7ae005ada8..1a41df3d0a 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, Google Inc. and others
+ * Copyright (C) 2010, 2020 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
@@ -123,7 +123,8 @@ public abstract class ContentSource {
WorkingTreeIterator ptr;
WorkingTreeSource(WorkingTreeIterator iterator) {
- this.tw = new TreeWalk((ObjectReader) null);
+ this.tw = new TreeWalk(iterator.getRepository(),
+ (ObjectReader) null);
this.tw.setRecursive(true);
this.iterator = iterator;
}
@@ -173,6 +174,15 @@ public abstract class ContentSource {
private void seek(String path) throws IOException {
if (!path.equals(current)) {
iterator.reset();
+ // Possibly this iterator had an associated DirCacheIterator,
+ // but we have no access to it and thus don't know about it.
+ // We have to reset this iterator here to work without
+ // DirCacheIterator and to descend always into ignored
+ // directories. Otherwise we might not find tracked files below
+ // ignored folders. Since we're looking only for a single
+ // specific path this is not a performance problem.
+ iterator.setWalkIgnoredDirectories(true);
+ iterator.setDirCacheIterator(null, -1);
tw.reset();
tw.addTree(iterator);
tw.setFilter(PathFilter.create(path));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index 81367eaa08..ec21954aa2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009, Google Inc.
- * Copyright (C) 2008-2009, Johannes E. Schindelin <johannes.schindelin@gmx.de> and others
+ * Copyright (C) 2008-2020, Johannes E. Schindelin <johannes.schindelin@gmx.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
@@ -502,9 +502,18 @@ public class DiffFormatter implements AutoCloseable {
throws IOException {
assertHaveReader();
- TreeWalk walk = new TreeWalk(reader);
- walk.addTree(a);
- walk.addTree(b);
+ TreeWalk walk = new TreeWalk(repository, reader);
+ int aIndex = walk.addTree(a);
+ int bIndex = walk.addTree(b);
+ if (repository != null) {
+ if (a instanceof WorkingTreeIterator
+ && b instanceof DirCacheIterator) {
+ ((WorkingTreeIterator) a).setDirCacheIterator(walk, bIndex);
+ } else if (b instanceof WorkingTreeIterator
+ && a instanceof DirCacheIterator) {
+ ((WorkingTreeIterator) b).setDirCacheIterator(walk, aIndex);
+ }
+ }
walk.setRecursive(true);
TreeFilter filter = getDiffTreeFilterFor(a, b);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index b2764d7804..03da61583d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2008-2010, Google Inc.
+ * Copyright (C) 2008, 2010, Google Inc.
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com> and others
+ * Copyright (C) 2011, 2020, Matthias Sohn <matthias.sohn@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -41,6 +41,9 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
import org.eclipse.jgit.internal.storage.file.LockFile;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Config.ConfigEnum;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
@@ -321,6 +324,9 @@ public class DirCache {
/** Repository containing this index */
private Repository repository;
+ /** If we read this index from disk, the original format. */
+ private DirCacheVersion version;
+
/**
* Create a new in-core index representation.
* <p>
@@ -364,6 +370,10 @@ public class DirCache {
return new DirCacheEditor(this, entryCnt + 16);
}
+ DirCacheVersion getVersion() {
+ return version;
+ }
+
void replace(DirCacheEntry[] e, int cnt) {
sortedEntries = e;
entryCnt = cnt;
@@ -445,13 +455,26 @@ public class DirCache {
md.update(hdr, 0, 12);
if (!is_DIRC(hdr))
throw new CorruptObjectException(JGitText.get().notADIRCFile);
- final int ver = NB.decodeInt32(hdr, 4);
+ int versionCode = NB.decodeInt32(hdr, 4);
+ DirCacheVersion ver = DirCacheVersion.fromInt(versionCode);
+ if (ver == null) {
+ throw new CorruptObjectException(
+ MessageFormat.format(JGitText.get().unknownDIRCVersion,
+ Integer.valueOf(versionCode)));
+ }
boolean extended = false;
- if (ver == 3)
+ switch (ver) {
+ case DIRC_VERSION_MINIMUM:
+ break;
+ case DIRC_VERSION_EXTENDED:
+ case DIRC_VERSION_PATHCOMPRESS:
extended = true;
- else if (ver != 2)
- throw new CorruptObjectException(MessageFormat.format(
- JGitText.get().unknownDIRCVersion, Integer.valueOf(ver)));
+ break;
+ default:
+ throw new CorruptObjectException(MessageFormat
+ .format(JGitText.get().unknownDIRCVersion, ver));
+ }
+ version = ver;
entryCnt = NB.decodeInt32(hdr, 8);
if (entryCnt < 0)
throw new CorruptObjectException(JGitText.get().DIRCHasTooManyEntries);
@@ -467,7 +490,8 @@ public class DirCache {
final MutableInteger infoAt = new MutableInteger();
for (int i = 0; i < entryCnt; i++) {
- sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md, smudge);
+ sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md, smudge,
+ version, i == 0 ? null : sortedEntries[i - 1]);
}
// After the file entries are index extensions, and then a footer.
@@ -606,11 +630,20 @@ public class DirCache {
final MessageDigest foot = Constants.newMessageDigest();
final DigestOutputStream dos = new DigestOutputStream(os, foot);
- boolean extended = false;
- for (int i = 0; i < entryCnt; i++) {
- if (sortedEntries[i].isExtended()) {
- extended = true;
- break;
+ if (version == null && this.repository != null) {
+ // A new DirCache is being written.
+ DirCacheConfig config = repository.getConfig()
+ .get(DirCacheConfig::new);
+ version = config.getIndexVersion();
+ }
+ if (version == null
+ || version == DirCacheVersion.DIRC_VERSION_MINIMUM) {
+ version = DirCacheVersion.DIRC_VERSION_MINIMUM;
+ for (int i = 0; i < entryCnt; i++) {
+ if (sortedEntries[i].isExtended()) {
+ version = DirCacheVersion.DIRC_VERSION_EXTENDED;
+ break;
+ }
}
}
@@ -618,7 +651,7 @@ public class DirCache {
//
final byte[] tmp = new byte[128];
System.arraycopy(SIG_DIRC, 0, tmp, 0, SIG_DIRC.length);
- NB.encodeInt32(tmp, 4, extended ? 3 : 2);
+ NB.encodeInt32(tmp, 4, version.getVersionCode());
NB.encodeInt32(tmp, 8, entryCnt);
dos.write(tmp, 0, 12);
@@ -650,7 +683,7 @@ public class DirCache {
if (e.mightBeRacilyClean(smudge)) {
e.smudgeRacilyClean();
}
- e.write(dos);
+ e.write(dos, version, i == 0 ? null : sortedEntries[i - 1]);
}
if (writeTree) {
@@ -982,4 +1015,76 @@ public class DirCache {
}
}
}
+
+ enum DirCacheVersion implements ConfigEnum {
+
+ /** Minimum index version on-disk format that we support. */
+ DIRC_VERSION_MINIMUM(2),
+ /** Version 3 supports extended flags. */
+ DIRC_VERSION_EXTENDED(3),
+ /**
+ * Version 4 adds very simple "path compression": it strips out the
+ * common prefix between the last entry written and the current entry.
+ * Instead of writing two entries with paths "foo/bar/baz/a.txt" and
+ * "foo/bar/baz/b.txt" it only writes "b.txt" for the second entry.
+ * <p>
+ * It is also <em>not</em> padded.
+ * </p>
+ */
+ DIRC_VERSION_PATHCOMPRESS(4);
+
+ private final int version;
+
+ private DirCacheVersion(int versionCode) {
+ this.version = versionCode;
+ }
+
+ public int getVersionCode() {
+ return version;
+ }
+
+ @Override
+ public String toConfigValue() {
+ return Integer.toString(version);
+ }
+
+ @Override
+ public boolean matchConfigValue(String in) {
+ try {
+ return version == Integer.parseInt(in);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ public static DirCacheVersion fromInt(int val) {
+ for (DirCacheVersion v : DirCacheVersion.values()) {
+ if (val == v.getVersionCode()) {
+ return v;
+ }
+ }
+ return null;
+ }
+ }
+
+ private static class DirCacheConfig {
+
+ private final DirCacheVersion indexVersion;
+
+ public DirCacheConfig(Config cfg) {
+ boolean manyFiles = cfg.getBoolean(
+ ConfigConstants.CONFIG_FEATURE_SECTION,
+ ConfigConstants.CONFIG_KEY_MANYFILES, false);
+ indexVersion = cfg.getEnum(DirCacheVersion.values(),
+ ConfigConstants.CONFIG_INDEX_SECTION, null,
+ ConfigConstants.CONFIG_KEY_VERSION,
+ manyFiles ? DirCacheVersion.DIRC_VERSION_PATHCOMPRESS
+ : DirCacheVersion.DIRC_VERSION_EXTENDED);
+ }
+
+ public DirCacheVersion getIndexVersion() {
+ return indexVersion;
+ }
+
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
index 73d2807eaf..8c342e267d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2008-2009, Google Inc.
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2009, Google Inc.
+ * Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -139,10 +139,28 @@ public class DirCacheEditor extends BaseDirCacheEditor {
: eIdx;
fastAdd(ent);
} else {
- // Apply to all entries of the current path (different stages)
lastIdx = cache.nextEntry(eIdx);
- for (int i = eIdx; i < lastIdx; i++) {
- final DirCacheEntry ent = cache.getEntry(i);
+ if (lastIdx > eIdx + 1) {
+ // Apply to all entries of the current path (different
+ // stages). If any apply() resets the stage to STAGE_0, take
+ // only that entry and omit all others.
+ DirCacheEntry[] tmp = new DirCacheEntry[lastIdx - eIdx];
+ int n = 0;
+ for (int i = eIdx; i < lastIdx; i++) {
+ DirCacheEntry ent = cache.getEntry(i);
+ e.apply(ent);
+ if (ent.getStage() == DirCacheEntry.STAGE_0) {
+ fastAdd(ent);
+ n = 0;
+ break;
+ }
+ tmp[n++] = ent;
+ }
+ for (int i = 0; i < n; i++) {
+ fastAdd(tmp[i]);
+ }
+ } else {
+ DirCacheEntry ent = cache.getEntry(eIdx);
e.apply(ent);
fastAdd(ent);
}
@@ -257,7 +275,9 @@ public class DirCacheEditor extends BaseDirCacheEditor {
* {@link #apply(DirCacheEntry)} method. The editor will invoke apply once
* for each record in the index which matches the path name. If there are
* multiple records (for example in stages 1, 2 and 3), the edit instance
- * will be called multiple times, once for each stage.
+ * will be called multiple times, once for each stage. If any of these calls
+ * resets the stage to 0, only this entry will be taken and entries for
+ * other stages are discarded.
*/
public abstract static class PathEdit {
final byte[] path;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index ced379ff1d..67edf50f44 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2008-2009, Google Inc.
+ * Copyright (C) 2008, 2009, Google Inc.
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
- * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> and others
+ * Copyright (C) 2010, 2020, Christian Halstrick <christian.halstrick@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -26,6 +26,7 @@ import java.text.MessageFormat;
import java.time.Instant;
import java.util.Arrays;
+import org.eclipse.jgit.dircache.DirCache.DirCacheVersion;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
@@ -112,15 +113,16 @@ public class DirCacheEntry {
/** Flags which are never stored to disk. */
private byte inCoreFlags;
- DirCacheEntry(final byte[] sharedInfo, final MutableInteger infoAt,
- final InputStream in, final MessageDigest md, final Instant smudge)
+ DirCacheEntry(byte[] sharedInfo, MutableInteger infoAt, InputStream in,
+ MessageDigest md, Instant smudge, DirCacheVersion version,
+ DirCacheEntry previous)
throws IOException {
info = sharedInfo;
infoOffset = infoAt.value;
IO.readFully(in, info, infoOffset, INFO_LEN);
- final int len;
+ int len;
if (isExtended()) {
len = INFO_LEN_EXTENDED;
IO.readFully(in, info, infoOffset + INFO_LEN, INFO_LEN_EXTENDED - INFO_LEN);
@@ -134,31 +136,66 @@ public class DirCacheEntry {
infoAt.value += len;
md.update(info, infoOffset, len);
+ int toRemove = 0;
+ if (version == DirCacheVersion.DIRC_VERSION_PATHCOMPRESS) {
+ // Read variable int and update digest
+ int b = in.read();
+ md.update((byte) b);
+ toRemove = b & 0x7F;
+ while ((b & 0x80) != 0) {
+ toRemove++;
+ b = in.read();
+ md.update((byte) b);
+ toRemove = (toRemove << 7) | (b & 0x7F);
+ }
+ if (toRemove < 0
+ || (previous != null && toRemove > previous.path.length)) {
+ if (previous == null) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().DIRCCorruptLengthFirst,
+ Integer.valueOf(toRemove)));
+ }
+ throw new IOException(MessageFormat.format(
+ JGitText.get().DIRCCorruptLength,
+ Integer.valueOf(toRemove), previous.getPathString()));
+ }
+ }
int pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;
int skipped = 0;
if (pathLen < NAME_MASK) {
path = new byte[pathLen];
- IO.readFully(in, path, 0, pathLen);
- md.update(path, 0, pathLen);
- } else {
- final ByteArrayOutputStream tmp = new ByteArrayOutputStream();
- {
- final byte[] buf = new byte[NAME_MASK];
- IO.readFully(in, buf, 0, NAME_MASK);
- tmp.write(buf);
- }
- for (;;) {
- final int c = in.read();
- if (c < 0)
- throw new EOFException(JGitText.get().shortReadOfBlock);
- if (c == 0)
- break;
- tmp.write(c);
+ if (version == DirCacheVersion.DIRC_VERSION_PATHCOMPRESS
+ && previous != null) {
+ System.arraycopy(previous.path, 0, path, 0,
+ previous.path.length - toRemove);
+ IO.readFully(in, path, previous.path.length - toRemove,
+ pathLen - (previous.path.length - toRemove));
+ md.update(path, previous.path.length - toRemove,
+ pathLen - (previous.path.length - toRemove));
+ pathLen = pathLen - (previous.path.length - toRemove);
+ } else {
+ IO.readFully(in, path, 0, pathLen);
+ md.update(path, 0, pathLen);
}
+ } else if (version != DirCacheVersion.DIRC_VERSION_PATHCOMPRESS
+ || previous == null || toRemove == previous.path.length) {
+ ByteArrayOutputStream tmp = new ByteArrayOutputStream();
+ byte[] buf = new byte[NAME_MASK];
+ IO.readFully(in, buf, 0, NAME_MASK);
+ tmp.write(buf);
+ readNulTerminatedString(in, tmp);
path = tmp.toByteArray();
pathLen = path.length;
- skipped = 1; // we already skipped 1 '\0' above to break the loop.
md.update(path, 0, pathLen);
+ skipped = 1; // we already skipped 1 '\0' in readNulTerminatedString
+ md.update((byte) 0);
+ } else {
+ ByteArrayOutputStream tmp = new ByteArrayOutputStream();
+ tmp.write(previous.path, 0, previous.path.length - toRemove);
+ pathLen = readNulTerminatedString(in, tmp);
+ path = tmp.toByteArray();
+ md.update(path, previous.path.length - toRemove, pathLen);
+ skipped = 1; // we already skipped 1 '\0' in readNulTerminatedString
md.update((byte) 0);
}
@@ -172,17 +209,26 @@ public class DirCacheEntry {
throw p;
}
- // Index records are padded out to the next 8 byte alignment
- // for historical reasons related to how C Git read the files.
- //
- final int actLen = len + pathLen;
- final int expLen = (actLen + 8) & ~7;
- final int padLen = expLen - actLen - skipped;
- if (padLen > 0) {
- IO.skipFully(in, padLen);
- md.update(nullpad, 0, padLen);
+ if (version == DirCacheVersion.DIRC_VERSION_PATHCOMPRESS) {
+ if (skipped == 0) {
+ int b = in.read();
+ if (b < 0) {
+ throw new EOFException(JGitText.get().shortReadOfBlock);
+ }
+ md.update((byte) b);
+ }
+ } else {
+ // Index records are padded out to the next 8 byte alignment
+ // for historical reasons related to how C Git read the files.
+ //
+ final int actLen = len + pathLen;
+ final int expLen = (actLen + 8) & ~7;
+ final int padLen = expLen - actLen - skipped;
+ if (padLen > 0) {
+ IO.skipFully(in, padLen);
+ md.update(nullpad, 0, padLen);
+ }
}
-
if (mightBeRacilyClean(smudge)) {
smudgeRacilyClean();
}
@@ -283,19 +329,61 @@ public class DirCacheEntry {
System.arraycopy(src.info, src.infoOffset, info, 0, INFO_LEN);
}
- void write(OutputStream os) throws IOException {
- final int len = isExtended() ? INFO_LEN_EXTENDED : INFO_LEN;
- final int pathLen = path.length;
- os.write(info, infoOffset, len);
- os.write(path, 0, pathLen);
+ private int readNulTerminatedString(InputStream in, OutputStream out)
+ throws IOException {
+ int n = 0;
+ for (;;) {
+ int c = in.read();
+ if (c < 0) {
+ throw new EOFException(JGitText.get().shortReadOfBlock);
+ }
+ if (c == 0) {
+ break;
+ }
+ out.write(c);
+ n++;
+ }
+ return n;
+ }
- // Index records are padded out to the next 8 byte alignment
- // for historical reasons related to how C Git read the files.
- //
- final int actLen = len + pathLen;
- final int expLen = (actLen + 8) & ~7;
- if (actLen != expLen)
- os.write(nullpad, 0, expLen - actLen);
+ void write(OutputStream os, DirCacheVersion version, DirCacheEntry previous)
+ throws IOException {
+ final int len = isExtended() ? INFO_LEN_EXTENDED : INFO_LEN;
+ if (version != DirCacheVersion.DIRC_VERSION_PATHCOMPRESS) {
+ os.write(info, infoOffset, len);
+ os.write(path, 0, path.length);
+ // Index records are padded out to the next 8 byte alignment
+ // for historical reasons related to how C Git read the files.
+ //
+ int entryLen = len + path.length;
+ int expLen = (entryLen + 8) & ~7;
+ if (entryLen != expLen)
+ os.write(nullpad, 0, expLen - entryLen);
+ } else {
+ int pathCommon = 0;
+ int toRemove;
+ if (previous != null) {
+ // Figure out common prefix
+ int pathLen = Math.min(path.length, previous.path.length);
+ while (pathCommon < pathLen
+ && path[pathCommon] == previous.path[pathCommon]) {
+ pathCommon++;
+ }
+ toRemove = previous.path.length - pathCommon;
+ } else {
+ toRemove = 0;
+ }
+ byte[] tmp = new byte[16];
+ int n = tmp.length;
+ tmp[--n] = (byte) (toRemove & 0x7F);
+ while ((toRemove >>>= 7) != 0) {
+ tmp[--n] = (byte) (0x80 | (--toRemove & 0x7F));
+ }
+ os.write(info, infoOffset, len);
+ os.write(tmp, n, tmp.length - n);
+ os.write(path, pathCommon, path.length - pathCommon);
+ os.write(0);
+ }
}
/**
@@ -454,6 +542,24 @@ public class DirCacheEntry {
}
/**
+ * Sets the stage of an entry.
+ *
+ * @param stage
+ * to set, in the range [0..3]
+ * @throws IllegalArgumentException
+ * if the stage is outside the range [0..3]
+ * @since 5.10
+ */
+ public void setStage(int stage) {
+ if ((stage & ~0x3) != 0) {
+ throw new IllegalArgumentException(
+ "Invalid stage, must be in range [0..3]"); //$NON-NLS-1$
+ }
+ byte flags = info[infoOffset + P_FLAGS];
+ info[infoOffset + P_FLAGS] = (byte) ((flags & 0xCF) | (stage << 4));
+ }
+
+ /**
* Returns whether this entry should be skipped from the working tree.
*
* @return true if this entry should be skipepd.
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 782a3f872d..892657d5d3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -230,10 +230,8 @@ public class JGitText extends TranslationBundle {
/***/ public String countingObjects;
/***/ public String createBranchFailedUnknownReason;
/***/ public String createBranchUnexpectedResult;
- /***/ public String createJGitConfigFailed;
/***/ public String createNewFileFailed;
/***/ public String createRequiresZeroOldId;
- /***/ public String createXDGConfigHomeFailed;
/***/ public String credentialPassword;
/***/ public String credentialPassphrase;
/***/ public String credentialUsername;
@@ -243,6 +241,7 @@ public class JGitText extends TranslationBundle {
/***/ public String deepenSinceWithDeepen;
/***/ public String deleteBranchUnexpectedResult;
/***/ public String deleteFileFailed;
+ /***/ public String deletedOrphanInPackDir;
/***/ public String deleteRequiresZeroNewId;
/***/ public String deleteTagUnexpectedResult;
/***/ public String deletingNotSupported;
@@ -252,6 +251,8 @@ public class JGitText extends TranslationBundle {
/***/ public String dirCacheFileIsNotLocked;
/***/ public String dirCacheIsNotLocked;
/***/ public String DIRCChecksumMismatch;
+ /***/ public String DIRCCorruptLength;
+ /***/ public String DIRCCorruptLengthFirst;
/***/ public String DIRCExtensionIsTooLargeAt;
/***/ public String DIRCExtensionNotSupportedByThisVersion;
/***/ public String DIRCHasTooManyEntries;
@@ -375,6 +376,9 @@ public class JGitText extends TranslationBundle {
/***/ public String invalidGitdirRef;
/***/ public String invalidGitModules;
/***/ public String invalidGitType;
+ /***/ public String invalidHeaderFormat;
+ /***/ public String invalidHeaderKey;
+ /***/ public String invalidHeaderValue;
/***/ public String invalidHexString;
/***/ public String invalidHomeDirectory;
/***/ public String invalidHooksPath;
@@ -436,6 +440,10 @@ public class JGitText extends TranslationBundle {
/***/ public String lockFailedRetry;
/***/ public String lockOnNotClosed;
/***/ public String lockOnNotHeld;
+ /***/ public String logInconsistentFiletimeDiff;
+ /***/ public String logLargerFiletimeDiff;
+ /***/ public String logSmallerFiletime;
+ /***/ public String logXDGConfigHomeInvalid;
/***/ public String maxCountMustBeNonNegative;
/***/ public String mergeConflictOnNonNoteEntries;
/***/ public String mergeConflictOnNotes;
@@ -649,6 +657,7 @@ public class JGitText extends TranslationBundle {
/***/ public String sourceRefNotSpecifiedForRefspec;
/***/ public String squashCommitNotUpdatingHEAD;
/***/ public String sshCommandFailed;
+ /***/ public String sshCommandTimeout;
/***/ public String sslFailureExceptionMessage;
/***/ public String sslFailureInfo;
/***/ public String sslFailureCause;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriter.java
new file mode 100644
index 0000000000..736f381d78
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBundleWriter.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, Google LLC 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
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.dfs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.internal.storage.pack.CachedPack;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.transport.BundleWriter;
+
+/** Writes {@link DfsRepository} to a Git bundle. */
+public class DfsBundleWriter {
+ /**
+ * Writes the entire {@link DfsRepository} to a Git bundle.
+ * <p>
+ * This method try to avoid traversing the pack files as much as possible
+ * and dumps all objects as-is to a Git bundle.
+ *
+ * @param pm
+ * progress monitor
+ * @param os
+ * Git bundle output
+ * @param db
+ * repository
+ * @throws IOException
+ * thrown if the output stream throws one.
+ */
+ public static void writeEntireRepositoryAsBundle(ProgressMonitor pm,
+ OutputStream os, DfsRepository db) throws IOException {
+ BundleWriter bw = new BundleWriter(db);
+ db.getRefDatabase().getRefs().forEach(bw::include);
+ List<CachedPack> packs = new ArrayList<>();
+ for (DfsPackFile p : db.getObjectDatabase().getPacks()) {
+ packs.add(new DfsCachedPack(p));
+ }
+ bw.addObjectsAsIs(packs);
+ bw.writeBundle(pm, os);
+ }
+
+ private DfsBundleWriter() {
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
index c9bb167f02..ec53818b4e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackBitmapIndex.java
@@ -59,12 +59,26 @@ abstract class BasePackBitmapIndex extends PackBitmapIndex {
* @return the full bitmap
*/
EWAHCompressedBitmap getBitmap() {
+ EWAHCompressedBitmap bitmap = getBitmapWithoutCaching();
+ // Cache the result.
+ bitmapContainer = bitmap;
+ return bitmap;
+ }
+
+ /**
+ * Compute and return the full bitmap, do NOT cache the expanded bitmap,
+ * which saves memory and should only be used during bitmap creation in
+ * garbage collection.
+ *
+ * @return the full bitmap
+ */
+ EWAHCompressedBitmap getBitmapWithoutCaching() {
// Fast path to immediately return the expanded result.
Object r = bitmapContainer;
if (r instanceof EWAHCompressedBitmap)
return (EWAHCompressedBitmap) r;
- // Expand the bitmap and cache the result.
+ // Expand the bitmap but not cache the result.
XorCompressedBitmap xb = (XorCompressedBitmap) r;
EWAHCompressedBitmap out = xb.bitmap;
for (;;) {
@@ -72,7 +86,6 @@ abstract class BasePackBitmapIndex extends PackBitmapIndex {
if (r instanceof EWAHCompressedBitmap) {
out = out.xor((EWAHCompressedBitmap) r);
out.trim();
- bitmapContainer = out;
return out;
}
xb = (XorCompressedBitmap) r;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index 0899578e20..1f2fe1057f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -115,6 +115,8 @@ public class GC {
private static final String INDEX_EXT = "." + PackExt.INDEX.getExtension(); //$NON-NLS-1$
+ private static final String KEEP_EXT = "." + PackExt.KEEP.getExtension(); //$NON-NLS-1$
+
private static final int DEFAULT_AUTOPACKLIMIT = 50;
private static final int DEFAULT_AUTOLIMIT = 6700;
@@ -961,11 +963,15 @@ public class GC {
fileNames = files.map(path -> path.getFileName().toString())
.filter(name -> (name.endsWith(PACK_EXT)
|| name.endsWith(BITMAP_EXT)
- || name.endsWith(INDEX_EXT)))
+ || name.endsWith(INDEX_EXT)
+ || name.endsWith(KEEP_EXT)))
+ // sort files with same base name in the order:
+ // .pack, .keep, .index, .bitmap to avoid look ahead
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
- } catch (IOException e1) {
- // ignore
+ } catch (IOException e) {
+ LOG.error(e.getMessage(), e);
+ return;
}
if (fileNames == null) {
return;
@@ -973,12 +979,15 @@ public class GC {
String base = null;
for (String n : fileNames) {
- if (n.endsWith(PACK_EXT)) {
+ if (n.endsWith(PACK_EXT) || n.endsWith(KEEP_EXT)) {
base = n.substring(0, n.lastIndexOf('.'));
} else {
if (base == null || !n.startsWith(base)) {
try {
- Files.delete(packDir.resolve(n));
+ Path delete = packDir.resolve(n);
+ FileUtils.delete(delete.toFile(),
+ FileUtils.RETRY | FileUtils.SKIP_MISSING);
+ LOG.warn(JGitText.get().deletedOrphanInPackDir, delete);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
@@ -1165,6 +1174,7 @@ public class GC {
// create temporary files
String id = pw.computeName().getName();
File packdir = repo.getObjectDatabase().getPackDirectory();
+ packdir.mkdirs();
tmpPack = File.createTempFile("gc_", ".pack_tmp", packdir); //$NON-NLS-1$ //$NON-NLS-2$
final String tmpBase = tmpPack.getName()
.substring(0, tmpPack.getName().lastIndexOf('.'));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 265b71dd2a..d32182864a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -580,7 +580,7 @@ public class ObjectDirectory extends FileObjectDatabase {
@Override
void selectObjectRepresentation(PackWriter packer, ObjectToPack otp,
- WindowCursor curs) throws IOException {
+ WindowCursor curs) throws IOException {
selectObjectRepresentation(packer, otp, curs, null);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
index 4b25284517..dd5d03c6e9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
@@ -156,7 +156,8 @@ public class PackBitmapIndexRemapper extends PackBitmapIndex
return null;
inflated.clear();
- for (IntIterator i = oldBitmap.getBitmap().intIterator(); i.hasNext();)
+ for (IntIterator i = oldBitmap.getBitmapWithoutCaching()
+ .intIterator(); i.hasNext();)
inflated.set(prevToNewMapping[i.next()]);
bitmap = inflated.toEWAHCompressedBitmap();
bitmap.trim();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
index 9cf95d0720..eb0ac6a062 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
@@ -49,11 +49,11 @@ class PackIndexV1 extends PackIndex {
idxHeader[k] = NB.decodeUInt32(fanoutTable, k * 4);
idxdata = new byte[idxHeader.length][];
for (int k = 0; k < idxHeader.length; k++) {
- int n;
+ long n;
if (k == 0) {
- n = (int) (idxHeader[k]);
+ n = idxHeader[k];
} else {
- n = (int) (idxHeader[k] - idxHeader[k - 1]);
+ n = idxHeader[k] - idxHeader[k - 1];
}
if (n > 0) {
final long len = n * (Constants.OBJECT_ID_LENGTH + 4);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
index 80c8e10dec..3e8cb3a3f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2008-2009, Google Inc.
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2009 Google Inc.
+ * Copyright (C) 2008, 2020 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
@@ -19,6 +19,7 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.atomic.LongAdder;
@@ -376,14 +377,14 @@ public class WindowCache {
* @return the cached instance.
*/
public static WindowCache getInstance() {
- return cache;
+ return cache.publishMBeanIfNeeded();
}
static final ByteWindow get(PackFile pack, long offset)
throws IOException {
final WindowCache c = cache;
final ByteWindow r = c.getOrLoad(pack, c.toStart(offset));
- if (c != cache) {
+ if (c != cache.publishMBeanIfNeeded()) {
// The cache was reconfigured while we were using the old one
// to load this window. The window is still valid, but our
// cache may think its still live. Ensure the window is removed
@@ -433,6 +434,8 @@ public class WindowCache {
private final StatsRecorderImpl mbean;
+ private final AtomicBoolean publishMBean = new AtomicBoolean();
+
private boolean useStrongRefs;
private WindowCache(WindowCacheConfig cfg) {
@@ -470,9 +473,7 @@ public class WindowCache {
mbean = new StatsRecorderImpl();
statsRecorder = mbean;
- if (cfg.getExposeStatsViaJmx()) {
- Monitoring.registerMBean(mbean, "block_cache"); //$NON-NLS-1$
- }
+ publishMBean.set(cfg.getExposeStatsViaJmx());
if (maxFiles < 1)
throw new IllegalArgumentException(JGitText.get().openFilesMustBeAtLeast1);
@@ -480,6 +481,13 @@ public class WindowCache {
throw new IllegalArgumentException(JGitText.get().windowSizeMustBeLesserThanLimit);
}
+ private WindowCache publishMBeanIfNeeded() {
+ if (publishMBean.getAndSet(false)) {
+ Monitoring.registerMBean(mbean, "block_cache"); //$NON-NLS-1$
+ }
+ return this;
+ }
+
/**
* @return cache statistics for the WindowCache
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 824c62ad9a..3e4b5df6aa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -756,6 +756,19 @@ public class PackWriter implements AutoCloseable {
/**
* Prepare the list of objects to be written to the pack stream.
+ *
+ * <p>
+ * PackWriter will concat and write out the specified packs as-is.
+ *
+ * @param c
+ * cached packs to be written.
+ */
+ public void preparePack(Collection<? extends CachedPack> c) {
+ cachedPacks.addAll(c);
+ }
+
+ /**
+ * Prepare the list of objects to be written to the pack stream.
* <p>
* Basing on these 2 sets, another set of objects to put in a pack file is
* created: this set consists of all objects reachable (ancestors) from
@@ -1548,6 +1561,7 @@ public class PackWriter implements AutoCloseable {
endPhase(monitor);
}
+ @SuppressWarnings("Finally")
private void parallelDeltaSearch(ProgressMonitor monitor,
ObjectToPack[] list, int cnt, int threads) throws IOException {
DeltaCache dc = new ThreadSafeDeltaCache(config);
@@ -1569,15 +1583,22 @@ public class PackWriter implements AutoCloseable {
// Caller didn't give us a way to run the tasks, spawn up a
// temporary thread pool and make sure it tears down cleanly.
ExecutorService pool = Executors.newFixedThreadPool(threads);
+ Throwable e1 = null;
try {
runTasks(pool, pm, taskBlock, errors);
+ } catch (Exception e) {
+ e1 = e;
} finally {
pool.shutdown();
for (;;) {
try {
- if (pool.awaitTermination(60, TimeUnit.SECONDS))
+ if (pool.awaitTermination(60, TimeUnit.SECONDS)) {
break;
+ }
} catch (InterruptedException e) {
+ if (e1 != null) {
+ e.addSuppressed(e1);
+ }
throw new IOException(JGitText
.get().packingCancelledDuringObjectsWriting, e);
}
@@ -2182,10 +2203,12 @@ public class PackWriter implements AutoCloseable {
// Check if this object needs to be rejected, doing the cheaper
// checks first.
- boolean reject = filterSpec.getBlobLimit() >= 0 &&
- type == OBJ_BLOB &&
- !want.contains(src) &&
- reader.getObjectSize(src, OBJ_BLOB) > filterSpec.getBlobLimit();
+ boolean reject =
+ (!filterSpec.allowsType(type) && !want.contains(src)) ||
+ (filterSpec.getBlobLimit() >= 0 &&
+ type == OBJ_BLOB &&
+ !want.contains(src) &&
+ reader.getObjectSize(src, OBJ_BLOB) > filterSpec.getBlobLimit());
if (!reject) {
addObject(src, type, pathHashCode);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
index 36335153a1..a78f4d24da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java
@@ -82,7 +82,7 @@ public class MergedReftable extends Reftable {
return 0;
}
long minUpdateIndex = tables[0].minUpdateIndex();
- for (int i = 0; i < tables.length - 1; i++) {
+ for (int i = 1; i < tables.length; i++) {
if (tables[i].minUpdateIndex() < minUpdateIndex) {
minUpdateIndex = tables[i].minUpdateIndex();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
index f6695bdf7d..b11b230a8f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
@@ -86,7 +86,7 @@ public interface BitmapIndex {
/**
* Returns the corresponding raw compressed EWAH bitmap of the bitmap.
- *
+ *
* @return the corresponding {@code EWAHCompressedBitmap}
* @since 5.8
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
index 66d7d51bdf..4f93fda49f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -361,7 +361,9 @@ public class CommitBuilder {
* header</a>.
* <p>
* CRLF and CR will be sanitized to LF and signature will have a hanging
- * indent of one space starting with line two.
+ * indent of one space starting with line two. A trailing line break is
+ * <em>not</em> written; the caller is supposed to terminate the GPG
+ * signature header by writing a single newline.
* </p>
*
* @param in
@@ -375,22 +377,24 @@ public class CommitBuilder {
*/
static void writeGpgSignatureString(String in, OutputStream out)
throws IOException, IllegalArgumentException {
- for (int i = 0; i < in.length(); ++i) {
+ int length = in.length();
+ for (int i = 0; i < length; ++i) {
char ch = in.charAt(i);
switch (ch) {
case '\r':
- if (i + 1 < in.length() && in.charAt(i + 1) == '\n') {
- out.write('\n');
- out.write(' ');
+ if (i + 1 < length && in.charAt(i + 1) == '\n') {
++i;
- } else {
+ }
+ if (i + 1 < length) {
out.write('\n');
out.write(' ');
}
break;
case '\n':
- out.write('\n');
- out.write(' ');
+ if (i + 1 < length) {
+ out.write('\n');
+ out.write(' ');
+ }
break;
default:
// sanity check
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
index a51593b509..a369026c97 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -20,6 +20,9 @@ package org.eclipse.jgit.lib;
import static java.nio.charset.StandardCharsets.UTF_8;
+import java.io.File;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
@@ -29,6 +32,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.events.ConfigChangedEvent;
import org.eclipse.jgit.events.ConfigChangedListener;
@@ -36,6 +40,7 @@ import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.ListenerList;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.RawParseUtils;
/**
@@ -475,6 +480,37 @@ public class Config {
}
/**
+ * Parse a string value and treat it as a file path, replacing a ~/ prefix
+ * by the user's home directory.
+ * <p>
+ * <b>Note:</b> this may throw {@link InvalidPathException} if the string is
+ * not a valid path.
+ * </p>
+ *
+ * @param section
+ * section the key is in.
+ * @param subsection
+ * subsection the key is in, or null if not in a subsection.
+ * @param name
+ * the key name.
+ * @param fs
+ * to use to convert the string into a path.
+ * @param resolveAgainst
+ * directory to resolve the path against if it is a relative
+ * path; {@code null} to use the Java process's current
+ * directory.
+ * @param defaultValue
+ * to return if no value was present
+ * @return the {@link Path}, or {@code defaultValue} if not set
+ * @since 5.10
+ */
+ public Path getPath(String section, String subsection, String name,
+ @NonNull FS fs, File resolveAgainst, Path defaultValue) {
+ return typedGetter.getPath(this, section, subsection, name, fs,
+ resolveAgainst, defaultValue);
+ }
+
+ /**
* Parse a list of {@link org.eclipse.jgit.transport.RefSpec}s from the
* configuration.
*
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 eef822fa4b..4fcf8e2dcd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
- * Copyright (C) 2012-2013, Robin Rosenberg and others
+ * Copyright (C) 2012, 2020, Robin Rosenberg and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -662,4 +662,33 @@ public final class ConfigConstants {
* @since 5.8
*/
public static final String CONFIG_KEY_WINDOW_MEMORY = "windowmemory";
+
+ /**
+ * The "feature" section
+ *
+ * @since 5.9
+ */
+ public static final String CONFIG_FEATURE_SECTION = "feature";
+
+ /**
+ * The "feature.manyFiles" key
+ *
+ * @since 5.9
+ */
+ public static final String CONFIG_KEY_MANYFILES = "manyFiles";
+
+ /**
+ * The "index" section
+ *
+ * @since 5.9
+ */
+ public static final String CONFIG_INDEX_SECTION = "index";
+
+ /**
+ * The "index.version" key
+ *
+ * @since 5.9
+ */
+ public static final String CONFIG_KEY_VERSION = "version";
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
index dd4be345e7..0f2f6cff8a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2017, 2020 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
@@ -10,22 +10,26 @@
package org.eclipse.jgit.lib;
+import java.io.File;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.util.FS;
/**
- * Something that knows how to convert plain strings from a git
- * {@link org.eclipse.jgit.lib.Config} to typed values.
+ * Something that knows how to convert plain strings from a git {@link Config}
+ * to typed values.
*
* @since 4.9
*/
public interface TypedConfigGetter {
/**
- * Get a boolean value from a git {@link org.eclipse.jgit.lib.Config}.
+ * Get a boolean value from a git {@link Config}.
*
* @param config
* to get the value from
@@ -44,7 +48,7 @@ public interface TypedConfigGetter {
String name, boolean defaultValue);
/**
- * Parse an enumeration from a git {@link org.eclipse.jgit.lib.Config}.
+ * Parse an enumeration from a git {@link Config}.
*
* @param config
* to get the value from
@@ -65,7 +69,7 @@ public interface TypedConfigGetter {
String subsection, String name, T defaultValue);
/**
- * Obtain an integer value from a git {@link org.eclipse.jgit.lib.Config}.
+ * Obtain an integer value from a git {@link Config}.
*
* @param config
* to get the value from
@@ -83,7 +87,7 @@ public interface TypedConfigGetter {
int defaultValue);
/**
- * Obtain a long value from a git {@link org.eclipse.jgit.lib.Config}.
+ * Obtain a long value from a git {@link Config}.
*
* @param config
* to get the value from
@@ -102,7 +106,7 @@ public interface TypedConfigGetter {
/**
* Parse a numerical time unit, such as "1 minute", from a git
- * {@link org.eclipse.jgit.lib.Config}.
+ * {@link Config}.
*
* @param config
* to get the value from
@@ -124,10 +128,50 @@ public interface TypedConfigGetter {
long getTimeUnit(Config config, String section, String subsection,
String name, long defaultValue, TimeUnit wantUnit);
+ /**
+ * Parse a string value from a git {@link Config} and treat it as a file
+ * path, replacing a ~/ prefix by the user's home directory.
+ * <p>
+ * <b>Note:</b> this may throw {@link InvalidPathException} if the string is
+ * not a valid path.
+ * </p>
+ *
+ * @param config
+ * to get the path from.
+ * @param section
+ * section the key is in.
+ * @param subsection
+ * subsection the key is in, or null if not in a subsection.
+ * @param name
+ * the key name.
+ * @param fs
+ * to use to convert the string into a path.
+ * @param resolveAgainst
+ * directory to resolve the path against if it is a relative
+ * path.
+ * @param defaultValue
+ * to return if no value was present
+ * @return the {@link Path}, or {@code defaultValue} if not set
+ * @since 5.10
+ */
+ default Path getPath(Config config, String section, String subsection,
+ String name, @NonNull FS fs, File resolveAgainst,
+ Path defaultValue) {
+ String value = config.getString(section, subsection, name);
+ if (value == null) {
+ return defaultValue;
+ }
+ File file;
+ if (value.startsWith("~/")) { //$NON-NLS-1$
+ file = fs.resolve(fs.userHome(), value.substring(2));
+ } else {
+ file = fs.resolve(resolveAgainst, value);
+ }
+ return file.toPath();
+ }
/**
- * Parse a list of {@link org.eclipse.jgit.transport.RefSpec}s from a git
- * {@link org.eclipse.jgit.lib.Config}.
+ * Parse a list of {@link RefSpec}s from a git {@link Config}.
*
* @param config
* to get the list from
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogContext.java b/org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogContext.java
new file mode 100644
index 0000000000..fab0dd102a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogContext.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020, Google LLC 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
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.logging;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Singleton that collects performance logs.
+ *
+ * @since 5.10
+ */
+public class PerformanceLogContext {
+ /** Singleton instance that stores the statistics. */
+ private static final PerformanceLogContext INSTANCE = new PerformanceLogContext();
+
+ /** List that stores events as performance logs. */
+ private static final ThreadLocal<List<PerformanceLogRecord>> eventRecords = ThreadLocal
+ .withInitial(ArrayList::new);
+
+ private PerformanceLogContext() {
+ }
+
+ /**
+ * Get the instance of the context.
+ *
+ * @return instance of performance log context.
+ */
+ public static PerformanceLogContext getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Get the unmodifiable list of events as performance records.
+ *
+ * @return unmodifiable list of events as performance logs.
+ */
+ public List<PerformanceLogRecord> getEventRecords() {
+ return Collections.unmodifiableList(eventRecords.get());
+ }
+
+ /**
+ * Adds a performance log record to the current list of events.
+ *
+ * @param record
+ * performance log record that is going to be added.
+ */
+ public void addEvent(PerformanceLogRecord record) {
+ eventRecords.get().add(record);
+ }
+
+ /**
+ * Removes all of the existing records from the current list of events.
+ */
+ public void cleanEvents() {
+ eventRecords.remove();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogRecord.java b/org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogRecord.java
new file mode 100644
index 0000000000..3dc5f20156
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/logging/PerformanceLogRecord.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020, Google LLC 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
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.logging;
+
+/**
+ * Class to register a performance log record.
+ *
+ * @since 5.10
+ */
+public class PerformanceLogRecord {
+ /** Name of the recorded event. */
+ private String name;
+
+ /** Duration of the recorded event in milliseconds. */
+ private long durationMs;
+
+ /**
+ * Create a new performance log record for an event.
+ *
+ * @param name
+ * name of the event.
+ * @param durationMs
+ * duration in milliseconds of the event.
+ */
+ public PerformanceLogRecord(String name, long durationMs) {
+ this.name = name;
+ this.durationMs = durationMs;
+ }
+
+ /**
+ * Get the name of the recorded event.
+ *
+ * @return name of the recorded event.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the duration in milliseconds of the recorded event.
+ *
+ * @return duration in milliseconds of the recorded event.
+ */
+ public long getDurationMs() {
+ return durationMs;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 506d333120..6c217fdf25 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -588,7 +588,8 @@ public class ResolveMerger extends ThreeWayMerger {
final int modeO = tw.getRawMode(T_OURS);
final int modeT = tw.getRawMode(T_THEIRS);
final int modeB = tw.getRawMode(T_BASE);
-
+ boolean gitLinkMerging = isGitLink(modeO) || isGitLink(modeT)
+ || isGitLink(modeB);
if (modeO == 0 && modeT == 0 && modeB == 0)
// File is either untracked or new, staged but uncommitted
return true;
@@ -737,31 +738,28 @@ public class ResolveMerger extends ThreeWayMerger {
return false;
}
- boolean gitlinkConflict = isGitLink(modeO) || isGitLink(modeT);
- // Don't attempt to resolve submodule link conflicts
- if (gitlinkConflict || !attributes.canBeContentMerged()) {
+ if (gitLinkMerging && ignoreConflicts) {
+ // Always select 'ours' in case of GITLINK merge failures so
+ // a caller can use virtual commit.
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0, EPOCH, 0);
+ return true;
+ } else if (gitLinkMerging) {
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
+ MergeResult<SubmoduleConflict> result = createGitLinksMergeResult(
+ base, ours, theirs);
+ result.setContainsConflicts(true);
+ mergeResults.put(tw.getPathString(), result);
+ unmergedPaths.add(tw.getPathString());
+ return true;
+ } else if (!attributes.canBeContentMerged()) {
add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
- if (gitlinkConflict) {
- MergeResult<SubmoduleConflict> result = new MergeResult<>(
- Arrays.asList(
- new SubmoduleConflict(base == null ? null
- : base.getEntryObjectId()),
- new SubmoduleConflict(ours == null ? null
- : ours.getEntryObjectId()),
- new SubmoduleConflict(theirs == null ? null
- : theirs.getEntryObjectId())));
- result.setContainsConflicts(true);
- mergeResults.put(tw.getPathString(), result);
- if (!ignoreConflicts) {
- unmergedPaths.add(tw.getPathString());
- }
- } else {
- // attribute merge issues are conflicts but not failures
- unmergedPaths.add(tw.getPathString());
- }
+ // attribute merge issues are conflicts but not failures
+ unmergedPaths.add(tw.getPathString());
return true;
}
@@ -786,45 +784,73 @@ public class ResolveMerger extends ThreeWayMerger {
// OURS or THEIRS has been deleted
if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
.idEqual(T_BASE, T_THEIRS)))) {
- MergeResult<RawText> result = contentMerge(base, ours, theirs,
- attributes);
-
- if (ignoreConflicts) {
- // In case a conflict is detected the working tree file is
- // again filled with new content (containing conflict
- // markers). But also stage 0 of the index is filled with
- // that content.
- result.setContainsConflicts(false);
- updateIndex(base, ours, theirs, result, attributes);
- } else {
+ if (gitLinkMerging && ignoreConflicts) {
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0, EPOCH, 0);
+ } else if (gitLinkMerging) {
add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
- DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_3, EPOCH, 0);
-
- // OURS was deleted checkout THEIRS
- if (modeO == 0) {
- // Check worktree before checking out THEIRS
- if (isWorktreeDirty(work, ourDce)) {
- return false;
- }
- if (nonTree(modeT)) {
- if (e != null) {
- addToCheckout(tw.getPathString(), e, attributes);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
+ MergeResult<SubmoduleConflict> result = createGitLinksMergeResult(
+ base, ours, theirs);
+ result.setContainsConflicts(true);
+ mergeResults.put(tw.getPathString(), result);
+ unmergedPaths.add(tw.getPathString());
+ } else {
+ MergeResult<RawText> result = contentMerge(base, ours,
+ theirs, attributes);
+
+ if (ignoreConflicts) {
+ // In case a conflict is detected the working tree file
+ // is again filled with new content (containing conflict
+ // markers). But also stage 0 of the index is filled
+ // with that content.
+ result.setContainsConflicts(false);
+ updateIndex(base, ours, theirs, result, attributes);
+ } else {
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH,
+ 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH,
+ 0);
+ DirCacheEntry e = add(tw.getRawPath(), theirs,
+ DirCacheEntry.STAGE_3, EPOCH, 0);
+
+ // OURS was deleted checkout THEIRS
+ if (modeO == 0) {
+ // Check worktree before checking out THEIRS
+ if (isWorktreeDirty(work, ourDce)) {
+ return false;
+ }
+ if (nonTree(modeT)) {
+ if (e != null) {
+ addToCheckout(tw.getPathString(), e,
+ attributes);
+ }
}
}
- }
- unmergedPaths.add(tw.getPathString());
+ unmergedPaths.add(tw.getPathString());
- // generate a MergeResult for the deleted file
- mergeResults.put(tw.getPathString(), result);
+ // generate a MergeResult for the deleted file
+ mergeResults.put(tw.getPathString(), result);
+ }
}
}
}
return true;
}
+ private static MergeResult<SubmoduleConflict> createGitLinksMergeResult(
+ CanonicalTreeParser base, CanonicalTreeParser ours,
+ CanonicalTreeParser theirs) {
+ return new MergeResult<>(Arrays.asList(
+ new SubmoduleConflict(
+ base == null ? null : base.getEntryObjectId()),
+ new SubmoduleConflict(
+ ours == null ? null : ours.getEntryObjectId()),
+ new SubmoduleConflict(
+ theirs == null ? null : theirs.getEntryObjectId())));
+ }
+
/**
* Does the content merge. The three texts base, ours and theirs are
* specified with {@link CanonicalTreeParser}. If any of the parsers is
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
index 645da0a068..4d18337fae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java
@@ -188,6 +188,13 @@ public class PackStatistics {
public long haves;
/**
+ * The count of wants that were not advertised by the server.
+ *
+ * @since 5.10
+ */
+ public long notAdvertisedWants;
+
+ /**
* Time in ms spent in the negotiation phase. For non-bidirectional
* transports (e.g., HTTP), this is only for the final request that
* sends back the pack file.
@@ -266,8 +273,16 @@ public class PackStatistics {
/** Time in ms spent writing the pack. */
public long timeWriting;
+ /** Time in ms spent checking reachability.
+ *
+ * @since 5.10
+ */
+ public long reachabilityCheckDuration;
+
/** Number of trees traversed in the walk when writing the pack.
- * @since 5.4*/
+ *
+ * @since 5.4
+ */
public long treesTraversed;
/**
@@ -349,6 +364,16 @@ public class PackStatistics {
}
/**
+ * Get the count of client wants that were not advertised by the server.
+ *
+ * @return count of client wants that were not advertised by the server.
+ * @since 5.10
+ */
+ public long getNotAdvertisedWants() {
+ return statistics.notAdvertisedWants;
+ }
+
+ /**
* Time in ms spent in the negotiation phase. For non-bidirectional
* transports (e.g., HTTP), this is only for the final request that sends
* back the pack file.
@@ -604,6 +629,18 @@ public class PackStatistics {
}
/**
+ * Get time in milliseconds spent checking if the client has access to the
+ * commits they are requesting.
+ *
+ * @return time in milliseconds spent checking if the client has access to the
+ * commits they are requesting.
+ * @since 5.10
+ */
+ public long getReachabilityCheckDuration() {
+ return statistics.reachabilityCheckDuration;
+ }
+
+ /**
* @return number of trees traversed in the walk when writing the pack.
* @since 5.4
*/
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
index 0ba5eb542d..bf77021b0c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -657,8 +657,11 @@ public class SubmoduleWalk implements AutoCloseable {
*
* @since 4.10
* @return name
+ * @throws ConfigInvalidException
+ * @throws IOException
*/
- public String getModuleName() {
+ public String getModuleName() throws IOException, ConfigInvalidException {
+ lazyLoadModulesConfig();
return getModuleName(path);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
index 1417faee80..3a36398629 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
@@ -21,8 +21,11 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.errors.InvalidObjectIdException;
@@ -35,6 +38,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.util.io.InterruptTimer;
import org.eclipse.jgit.util.io.TimeoutInputStream;
import org.eclipse.jgit.util.io.TimeoutOutputStream;
@@ -49,6 +53,8 @@ import org.eclipse.jgit.util.io.TimeoutOutputStream;
*/
abstract class BasePackConnection extends BaseConnection {
+ protected static final String CAPABILITY_SYMREF_PREFIX = "symref="; //$NON-NLS-1$
+
/** The repository this transport fetches into, or pushes out of. */
protected final Repository local;
@@ -228,10 +234,109 @@ abstract class BasePackConnection extends BaseConnection {
throw duplicateAdvertisement(name);
}
}
+ updateWithSymRefs(avail, extractSymRefsFromCapabilities(remoteCapablities));
available(avail);
}
/**
+ * Finds values in the given capabilities of the form:
+ *
+ * <pre>
+ * symref=<em>source</em>:<em>target</em>
+ * </pre>
+ *
+ * And returns a Map of source->target entries.
+ *
+ * @param capabilities
+ * the capabilities lines
+ * @return a Map of the symref entries from capabilities
+ * @throws NullPointerException
+ * if capabilities, or any entry in it, is null
+ */
+ static Map<String, String> extractSymRefsFromCapabilities(Collection<String> capabilities) {
+ final Map<String, String> symRefs = new LinkedHashMap<>();
+ for (String option : capabilities) {
+ if (option.startsWith(CAPABILITY_SYMREF_PREFIX)) {
+ String[] symRef = option
+ .substring(CAPABILITY_SYMREF_PREFIX.length())
+ .split(":", 2); //$NON-NLS-1$
+ if (symRef.length == 2) {
+ symRefs.put(symRef[0], symRef[1]);
+ }
+ }
+ }
+ return symRefs;
+ }
+
+ /**
+ * Updates the given refMap with {@link SymbolicRef}s defined by the given
+ * symRefs.
+ * <p>
+ * For each entry, symRef, in symRefs, whose value is a key in refMap, adds
+ * a new entry to refMap with that same key and value of a new
+ * {@link SymbolicRef} with source=symRef.key and
+ * target=refMap.get(symRef.value), then removes that entry from symRefs.
+ * <p>
+ * If refMap already contains an entry for symRef.key, it is replaced.
+ * </p>
+ * </p>
+ * <p>
+ * For example, given:
+ * </p>
+ *
+ * <pre>
+ * refMap.put("refs/heads/main", ref);
+ * symRefs.put("HEAD", "refs/heads/main");
+ * </pre>
+ *
+ * then:
+ *
+ * <pre>
+ * updateWithSymRefs(refMap, symRefs);
+ * </pre>
+ *
+ * has the <em>effect</em> of:
+ *
+ * <pre>
+ * refMap.put("HEAD",
+ * new SymbolicRef("HEAD", refMap.get(symRefs.remove("HEAD"))))
+ * </pre>
+ * <p>
+ * Any entry in symRefs whose value is not a key in refMap is ignored. Any
+ * circular symRefs are ignored.
+ * </p>
+ * <p>
+ * Upon completion, symRefs will contain only any unresolvable entries.
+ * </p>
+ *
+ * @param refMap
+ * a non-null, modifiable, Map to update, and the provider of
+ * symref targets.
+ * @param symRefs
+ * a non-null, modifiable, Map of symrefs.
+ * @throws NullPointerException
+ * if refMap or symRefs is null
+ */
+ static void updateWithSymRefs(Map<String, Ref> refMap, Map<String, String> symRefs) {
+ boolean haveNewRefMapEntries = !refMap.isEmpty();
+ while (!symRefs.isEmpty() && haveNewRefMapEntries) {
+ haveNewRefMapEntries = false;
+ final Iterator<Map.Entry<String, String>> iterator = symRefs.entrySet().iterator();
+ while (iterator.hasNext()) {
+ final Map.Entry<String, String> symRef = iterator.next();
+ if (!symRefs.containsKey(symRef.getValue())) { // defer forward reference
+ final Ref r = refMap.get(symRef.getValue());
+ if (r != null) {
+ refMap.put(symRef.getKey(), new SymbolicRef(symRef.getKey(), r));
+ haveNewRefMapEntries = true;
+ iterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Create an exception to indicate problems finding a remote repository. The
* caller is expected to throw the returned exception.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index 57eed3ad2a..4649d33ff8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -17,12 +17,16 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.CachedPack;
import org.eclipse.jgit.internal.storage.pack.PackWriter;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
@@ -62,6 +66,8 @@ public class BundleWriter {
private final Set<ObjectId> tagTargets;
+ private final List<CachedPack> cachedPacks = new ArrayList<>();
+
private PackConfig packConfig;
private ObjectCountCallback callback;
@@ -150,6 +156,26 @@ public class BundleWriter {
}
/**
+ * Add objects to the bundle file.
+ *
+ * <p>
+ * When this method is used, object traversal is disabled and specified pack
+ * files are directly saved to the Git bundle file.
+ *
+ * <p>
+ * Unlike {@link #include}, this doesn't affect the refs. Even if the
+ * objects are not reachable from any ref, they will be included in the
+ * bundle file.
+ *
+ * @param c
+ * pack to include
+ * @since 5.9
+ */
+ public void addObjectsAsIs(Collection<? extends CachedPack> c) {
+ cachedPacks.addAll(c);
+ }
+
+ /**
* Assume a commit is available on the recipient's side.
* <p>
* In order to fetch from a bundle the recipient must have any assumed
@@ -187,19 +213,24 @@ public class BundleWriter {
try (PackWriter packWriter = newPackWriter()) {
packWriter.setObjectCountCallback(callback);
- final HashSet<ObjectId> inc = new HashSet<>();
- final HashSet<ObjectId> exc = new HashSet<>();
- inc.addAll(include.values());
- for (RevCommit r : assume)
- exc.add(r.getId());
packWriter.setIndexDisabled(true);
packWriter.setDeltaBaseAsOffset(true);
- packWriter.setThin(!exc.isEmpty());
packWriter.setReuseValidatingObjects(false);
- if (exc.isEmpty()) {
- packWriter.setTagTargets(tagTargets);
+ if (cachedPacks.isEmpty()) {
+ HashSet<ObjectId> inc = new HashSet<>();
+ HashSet<ObjectId> exc = new HashSet<>();
+ inc.addAll(include.values());
+ for (RevCommit r : assume) {
+ exc.add(r.getId());
+ }
+ if (exc.isEmpty()) {
+ packWriter.setTagTargets(tagTargets);
+ }
+ packWriter.setThin(!exc.isEmpty());
+ packWriter.preparePack(monitor, inc, exc);
+ } else {
+ packWriter.preparePack(cachedPacks);
}
- packWriter.preparePack(monitor, inc, exc);
final Writer w = new OutputStreamWriter(os, UTF_8);
w.write(TransportBundle.V2_BUNDLE_SIGNATURE);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FilterSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FilterSpec.java
index d09b5579fa..a8cf849fed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FilterSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FilterSpec.java
@@ -10,6 +10,15 @@
package org.eclipse.jgit.transport;
+import static java.math.BigInteger.ZERO;
+import static java.util.Objects.requireNonNull;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_FILTER;
+
+import java.math.BigInteger;
import java.text.MessageFormat;
import org.eclipse.jgit.annotations.Nullable;
@@ -24,11 +33,54 @@ import org.eclipse.jgit.internal.JGitText;
*/
public final class FilterSpec {
+ /** Immutable bit-set representation of a set of Git object types. */
+ static class ObjectTypes {
+ static ObjectTypes ALL = allow(OBJ_BLOB, OBJ_TREE, OBJ_COMMIT, OBJ_TAG);
+
+ private final BigInteger val;
+
+ private ObjectTypes(BigInteger val) {
+ this.val = requireNonNull(val);
+ }
+
+ static ObjectTypes allow(int... types) {
+ BigInteger bits = ZERO;
+ for (int type : types) {
+ bits = bits.setBit(type);
+ }
+ return new ObjectTypes(bits);
+ }
+
+ boolean contains(int type) {
+ return val.testBit(type);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ObjectTypes)) {
+ return false;
+ }
+
+ ObjectTypes other = (ObjectTypes) obj;
+ return other.val.equals(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return val.hashCode();
+ }
+ }
+
+ private final ObjectTypes types;
+
private final long blobLimit;
private final long treeDepthLimit;
- private FilterSpec(long blobLimit, long treeDepthLimit) {
+ private FilterSpec(ObjectTypes types, long blobLimit, long treeDepthLimit) {
+ this.types = requireNonNull(types);
this.blobLimit = blobLimit;
this.treeDepthLimit = treeDepthLimit;
}
@@ -53,7 +105,8 @@ public final class FilterSpec {
public static FilterSpec fromFilterLine(String filterLine)
throws PackProtocolException {
if (filterLine.equals("blob:none")) { //$NON-NLS-1$
- return FilterSpec.withBlobLimit(0);
+ return FilterSpec.withObjectTypes(
+ ObjectTypes.allow(OBJ_TREE, OBJ_COMMIT, OBJ_TAG));
} else if (filterLine.startsWith("blob:limit=")) { //$NON-NLS-1$
long blobLimit = -1;
try {
@@ -86,8 +139,18 @@ public final class FilterSpec {
}
/**
+ * @param types
+ * set of permitted object types, for use in "blob:none" and
+ * "object:none" filters
+ * @return a filter spec which restricts to objects of the specified types
+ */
+ static FilterSpec withObjectTypes(ObjectTypes types) {
+ return new FilterSpec(types, -1, -1);
+ }
+
+ /**
* @param blobLimit
- * the blob limit in a "blob:[limit]" or "blob:none" filter line
+ * the blob limit in a "blob:[limit]" filter line
* @return a filter spec which filters blobs above a certain size
*/
static FilterSpec withBlobLimit(long blobLimit) {
@@ -95,7 +158,7 @@ public final class FilterSpec {
throw new IllegalArgumentException(
"blobLimit cannot be negative: " + blobLimit); //$NON-NLS-1$
}
- return new FilterSpec(blobLimit, -1);
+ return new FilterSpec(ObjectTypes.ALL, blobLimit, -1);
}
/**
@@ -109,13 +172,25 @@ public final class FilterSpec {
throw new IllegalArgumentException(
"treeDepthLimit cannot be negative: " + treeDepthLimit); //$NON-NLS-1$
}
- return new FilterSpec(-1, treeDepthLimit);
+ return new FilterSpec(ObjectTypes.ALL, -1, treeDepthLimit);
}
/**
* A placeholder that indicates no filtering.
*/
- public static final FilterSpec NO_FILTER = new FilterSpec(-1, -1);
+ public static final FilterSpec NO_FILTER = new FilterSpec(ObjectTypes.ALL, -1, -1);
+
+ /**
+ * @param type
+ * a Git object type, such as
+ * {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB}
+ * @return whether this filter allows objects of the specified type
+ *
+ * @since 5.9
+ */
+ public boolean allowsType(int type) {
+ return types.contains(type);
+ }
/**
* @return -1 if this filter does not filter blobs based on size, or a
@@ -138,7 +213,7 @@ public final class FilterSpec {
* @return true if this filter doesn't filter out anything
*/
public boolean isNoOp() {
- return blobLimit == -1 && treeDepthLimit == -1;
+ return types.equals(ObjectTypes.ALL) && blobLimit == -1 && treeDepthLimit == -1;
}
/**
@@ -146,14 +221,17 @@ public final class FilterSpec {
*/
@Nullable
public String filterLine() {
- if (blobLimit == 0) {
- return GitProtocolConstants.OPTION_FILTER + " blob:none"; //$NON-NLS-1$
+ if (isNoOp()) {
+ return null;
+ } else if (types.equals(ObjectTypes.allow(OBJ_TREE, OBJ_COMMIT, OBJ_TAG)) &&
+ blobLimit == -1 && treeDepthLimit == -1) {
+ return OPTION_FILTER + " blob:none"; //$NON-NLS-1$
+ } else if (types.equals(ObjectTypes.ALL) && blobLimit >= 0 && treeDepthLimit == -1) {
+ return OPTION_FILTER + " blob:limit=" + blobLimit; //$NON-NLS-1$
+ } else if (types.equals(ObjectTypes.ALL) && blobLimit == -1 && treeDepthLimit >= 0) {
+ return OPTION_FILTER + " tree:" + treeDepthLimit; //$NON-NLS-1$
+ } else {
+ throw new IllegalStateException();
}
-
- if (blobLimit > 0) {
- return GitProtocolConstants.OPTION_FILTER + " blob:limit=" + blobLimit; //$NON-NLS-1$
- }
-
- return null;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
index 79cba80e11..dc82f46197 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
@@ -14,9 +14,13 @@ package org.eclipse.jgit.transport;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Config;
@@ -56,6 +60,20 @@ public class HttpConfig {
public static final String SSL_VERIFY_KEY = "sslVerify"; //$NON-NLS-1$
/**
+ * git config key for the "userAgent" setting.
+ *
+ * @since 5.10
+ */
+ public static final String USER_AGENT = "userAgent"; //$NON-NLS-1$
+
+ /**
+ * git config key for the "extraHeader" setting.
+ *
+ * @since 5.10
+ */
+ public static final String EXTRA_HEADER = "extraHeader"; //$NON-NLS-1$
+
+ /**
* git config key for the "cookieFile" setting.
*
* @since 5.4
@@ -103,6 +121,8 @@ public class HttpConfig {
}
}).get().intValue();
+ private static final String ENV_HTTP_USER_AGENT = "GIT_HTTP_USER_AGENT"; //$NON-NLS-1$
+
/**
* Config values for http.followRedirect.
*/
@@ -143,6 +163,10 @@ public class HttpConfig {
private int maxRedirects;
+ private String userAgent;
+
+ private List<String> extraHeaders;
+
private String cookieFile;
private boolean saveCookies;
@@ -186,6 +210,27 @@ public class HttpConfig {
}
/**
+ * Get the "http.userAgent" setting
+ *
+ * @return the value of the "http.userAgent" setting
+ * @since 5.10
+ */
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ /**
+ * Get the "http.extraHeader" setting
+ *
+ * @return the value of the "http.extraHeader" setting
+ * @since 5.10
+ */
+ @NonNull
+ public List<String> getExtraHeaders() {
+ return extraHeaders == null ? Collections.emptyList() : extraHeaders;
+ }
+
+ /**
* Get the "http.cookieFile" setting
*
* @return the value of the "http.cookieFile" setting
@@ -265,11 +310,25 @@ public class HttpConfig {
if (redirectLimit < 0) {
redirectLimit = MAX_REDIRECTS;
}
+ String agent = config.getString(HTTP, null, USER_AGENT);
+ if (agent != null) {
+ agent = UserAgent.clean(agent);
+ }
+ userAgent = agent;
+ String[] headers = config.getStringList(HTTP, null, EXTRA_HEADER);
+ // https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpextraHeader
+ // "an empty value will reset the extra headers to the empty list."
+ int start = findLastEmpty(headers) + 1;
+ if (start > 0) {
+ headers = Arrays.copyOfRange(headers, start, headers.length);
+ }
+ extraHeaders = Arrays.asList(headers);
cookieFile = config.getString(HTTP, null, COOKIE_FILE_KEY);
saveCookies = config.getBoolean(HTTP, SAVE_COOKIES_KEY, false);
cookieFileCacheLimit = config.getInt(HTTP, COOKIE_FILE_CACHE_LIMIT_KEY,
DEFAULT_COOKIE_FILE_CACHE_LIMIT);
String match = findMatch(config.getSubsections(HTTP), uri);
+
if (match != null) {
// Override with more specific items
postBufferSize = config.getInt(HTTP, match, POST_BUFFER_KEY,
@@ -283,6 +342,22 @@ public class HttpConfig {
if (newMaxRedirects >= 0) {
redirectLimit = newMaxRedirects;
}
+ String uriSpecificUserAgent = config.getString(HTTP, match,
+ USER_AGENT);
+ if (uriSpecificUserAgent != null) {
+ userAgent = UserAgent.clean(uriSpecificUserAgent);
+ }
+ String[] uriSpecificExtraHeaders = config.getStringList(HTTP, match,
+ EXTRA_HEADER);
+ if (uriSpecificExtraHeaders.length > 0) {
+ start = findLastEmpty(uriSpecificExtraHeaders) + 1;
+ if (start > 0) {
+ uriSpecificExtraHeaders = Arrays.copyOfRange(
+ uriSpecificExtraHeaders, start,
+ uriSpecificExtraHeaders.length);
+ }
+ extraHeaders = Arrays.asList(uriSpecificExtraHeaders);
+ }
String urlSpecificCookieFile = config.getString(HTTP, match,
COOKIE_FILE_KEY);
if (urlSpecificCookieFile != null) {
@@ -291,12 +366,26 @@ public class HttpConfig {
saveCookies = config.getBoolean(HTTP, match, SAVE_COOKIES_KEY,
saveCookies);
}
+ // Environment overrides config
+ agent = SystemReader.getInstance().getenv(ENV_HTTP_USER_AGENT);
+ if (!StringUtils.isEmptyOrNull(agent)) {
+ userAgent = UserAgent.clean(agent);
+ }
postBuffer = postBufferSize;
sslVerify = sslVerifyFlag;
followRedirects = followRedirectsMode;
maxRedirects = redirectLimit;
}
+ private int findLastEmpty(String[] values) {
+ for (int i = values.length - 1; i >= 0; i--) {
+ if (values[i] == null) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
/**
* Determines the best match from a set of subsection names (representing
* prefix URLs) for the given {@link URIish}.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 0801b8a86a..715cbb48fb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -679,7 +679,8 @@ public abstract class PackParser {
verifySafeObject(tempObjectId, type, visit.data);
if (isCheckObjectCollisions() && readCurs.has(tempObjectId)) {
- checkObjectCollision(tempObjectId, type, visit.data);
+ checkObjectCollision(tempObjectId, type, visit.data,
+ visit.delta.sizeBeforeInflating);
}
PackedObjectInfo oe;
@@ -999,6 +1000,7 @@ public abstract class PackParser {
UnresolvedDelta n = onEndDelta();
n.position = streamPosition;
n.next = baseByPos.put(base, n);
+ n.sizeBeforeInflating = streamPosition() - streamPosition;
deltaCount++;
break;
}
@@ -1020,6 +1022,7 @@ public abstract class PackParser {
inflateAndSkip(Source.INPUT, sz);
UnresolvedDelta n = onEndDelta();
n.position = streamPosition;
+ n.sizeBeforeInflating = streamPosition() - streamPosition;
r.add(n);
deltaCount++;
break;
@@ -1071,9 +1074,11 @@ public abstract class PackParser {
verifySafeObject(tempObjectId, type, data);
}
+ long sizeBeforeInflating = streamPosition() - pos;
PackedObjectInfo obj = newInfo(tempObjectId, null, null);
obj.setOffset(pos);
obj.setType(type);
+ obj.setSize(sizeBeforeInflating);
onEndWholeObject(obj);
if (data != null)
onInflatedObjectData(obj, type, data);
@@ -1148,6 +1153,8 @@ public abstract class PackParser {
sz -= n;
}
}
+ stats.incrementObjectsDuplicated();
+ stats.incrementNumBytesDuplicated(obj.getSize());
} catch (MissingObjectException notLocal) {
// This is OK, we don't have a copy of the object locally
// but the API throws when we try to read it as usually it's
@@ -1155,15 +1162,17 @@ public abstract class PackParser {
}
}
- private void checkObjectCollision(AnyObjectId obj, int type, byte[] data)
- throws IOException {
+ private void checkObjectCollision(AnyObjectId obj, int type, byte[] data,
+ long sizeBeforeInflating) throws IOException {
try {
final ObjectLoader ldr = readCurs.open(obj, type);
final byte[] existingData = ldr.getCachedBytes(data.length);
if (!Arrays.equals(data, existingData)) {
- throw new IOException(MessageFormat.format(
- JGitText.get().collisionOn, obj.name()));
+ throw new IOException(MessageFormat
+ .format(JGitText.get().collisionOn, obj.name()));
}
+ stats.incrementObjectsDuplicated();
+ stats.incrementNumBytesDuplicated(sizeBeforeInflating);
} catch (MissingObjectException notLocal) {
// This is OK, we don't have a copy of the object locally
// but the API throws when we try to read it as usually its
@@ -1653,6 +1662,8 @@ public abstract class PackParser {
UnresolvedDelta next;
+ long sizeBeforeInflating;
+
/** @return offset within the input stream. */
public long getOffset() {
return position;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
index fc906de2a8..fe1209b6af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackedObjectInfo.java
@@ -29,6 +29,8 @@ public class PackedObjectInfo extends ObjectIdOwnerMap.Entry {
private int type = Constants.OBJ_BAD;
+ private long sizeBeforeInflating;
+
PackedObjectInfo(final long headerOffset, final int packedCRC,
final AnyObjectId id) {
super(id);
@@ -108,4 +110,12 @@ public class PackedObjectInfo extends ObjectIdOwnerMap.Entry {
public void setType(int type) {
this.type = type;
}
+
+ void setSize(long sizeBeforeInflating) {
+ this.sizeBeforeInflating = sizeBeforeInflating;
+ }
+
+ long getSize() {
+ return sizeBeforeInflating;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
index 52a5576e43..350311ecc8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2008-2010, Google Inc.
- * Copyright (C) 2008-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2010 Google Inc.
+ * Copyright (C) 2008, 2009 Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, 2020 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
@@ -50,7 +50,7 @@ public class PacketLineIn {
* strings in the input stream until the marker is reached.
*/
@Deprecated
- public static final String END = new StringBuilder(0).toString(); /* must not string pool */
+ public static final String END = new String(); /* must not string pool */
/**
* Magic return from {@link #readString()} when a delim packet is found.
@@ -60,7 +60,7 @@ public class PacketLineIn {
* string is the delimiter.
*/
@Deprecated
- public static final String DELIM = new StringBuilder(0).toString(); /* must not string pool */
+ public static final String DELIM = new String(); /* must not string pool */
enum AckNackResult {
/** NAK */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
index bd8f5585d2..d7bc40006b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
@@ -19,6 +19,7 @@ import org.eclipse.jgit.lib.Constants;
*/
public class ReceivedPackStatistics {
private long numBytesRead;
+ private long numBytesDuplicated;
private long numWholeCommit;
private long numWholeTree;
@@ -26,6 +27,7 @@ public class ReceivedPackStatistics {
private long numWholeTag;
private long numOfsDelta;
private long numRefDelta;
+ private long numObjectsDuplicated;
private long numDeltaCommit;
private long numDeltaTree;
@@ -42,6 +44,17 @@ public class ReceivedPackStatistics {
}
/**
+ * Get number of bytes of objects already in the local database
+ *
+ * @return number of bytes of objects appeared in both the pack sent by the
+ * client and the local database
+ * @since 5.10
+ */
+ public long getNumBytesDuplicated() {
+ return numBytesDuplicated;
+ }
+
+ /**
* Get number of whole commit objects in the pack
*
* @return number of whole commit objects in the pack
@@ -96,6 +109,17 @@ public class ReceivedPackStatistics {
}
/**
+ * Get number of objects already in the local database
+ *
+ * @return number of objects appeared in both the pack sent by the client
+ * and the local database
+ * @since 5.10
+ */
+ public long getNumObjectsDuplicated() {
+ return numObjectsDuplicated;
+ }
+
+ /**
* Get number of delta commit objects in the pack
*
* @return number of delta commit objects in the pack
@@ -134,6 +158,7 @@ public class ReceivedPackStatistics {
/** A builder for {@link ReceivedPackStatistics}. */
public static class Builder {
private long numBytesRead;
+ private long numBytesDuplicated;
private long numWholeCommit;
private long numWholeTree;
@@ -141,6 +166,7 @@ public class ReceivedPackStatistics {
private long numWholeTag;
private long numOfsDelta;
private long numRefDelta;
+ private long numObjectsDuplicated;
private long numDeltaCommit;
private long numDeltaTree;
@@ -157,6 +183,17 @@ public class ReceivedPackStatistics {
}
/**
+ * @param size
+ * additional bytes already in the local database
+ * @return this
+ * @since 5.10
+ */
+ Builder incrementNumBytesDuplicated(long size) {
+ numBytesDuplicated += size;
+ return this;
+ }
+
+ /**
* Increment a whole object count.
*
* @param type OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, or OBJ_TAG
@@ -196,6 +233,17 @@ public class ReceivedPackStatistics {
}
/**
+ * Increment the duplicated object count.
+ *
+ * @return this
+ * @since 5.10
+ */
+ Builder incrementObjectsDuplicated() {
+ numObjectsDuplicated++;
+ return this;
+ }
+
+ /**
* Increment a delta object count.
*
* @param type OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, or OBJ_TAG
@@ -226,6 +274,7 @@ public class ReceivedPackStatistics {
ReceivedPackStatistics build() {
ReceivedPackStatistics s = new ReceivedPackStatistics();
s.numBytesRead = numBytesRead;
+ s.numBytesDuplicated = numBytesDuplicated;
s.numWholeCommit = numWholeCommit;
s.numWholeTree = numWholeTree;
s.numWholeBlob = numWholeBlob;
@@ -236,6 +285,7 @@ public class ReceivedPackStatistics {
s.numDeltaTree = numDeltaTree;
s.numDeltaBlob = numDeltaBlob;
s.numDeltaTag = numDeltaTag;
+ s.numObjectsDuplicated = numObjectsDuplicated;
return s;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
index f9f50d46e7..dd4c967f91 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteSession.java
@@ -4,7 +4,7 @@
* Copyright (C) 2009, Google, Inc.
* Copyright (C) 2009, JetBrains s.r.o.
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2020 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
@@ -18,26 +18,20 @@ package org.eclipse.jgit.transport;
import java.io.IOException;
/**
- * Create a remote "session" for executing remote commands.
- * <p>
- * Clients should subclass RemoteSession to create an alternate way for JGit to
- * execute remote commands. (The client application may already have this
- * functionality available.) Note that this class is just a factory for creating
- * remote processes. If the application already has a persistent connection to
- * the remote machine, RemoteSession may do nothing more than return a new
- * RemoteProcess when exec is called.
+ * An abstraction of a remote "session" for executing remote commands.
*/
public interface RemoteSession {
+
/**
- * Generate a new remote process to execute the given command. This function
- * should also start execution and may need to create the streams prior to
- * execution.
+ * Creates a new remote {@link Process} to execute the given command. The
+ * returned process's streams exist and are connected, and execution of the
+ * process is already started.
*
* @param commandName
* command to execute
* @param timeout
- * timeout value, in seconds, for command execution
- * @return a new remote process
+ * timeout value, in seconds, for creating the remote process
+ * @return a new remote process, already started
* @throws java.io.IOException
* may be thrown in several cases. For example, on problems
* opening input or output streams or on problems connecting or
@@ -48,7 +42,7 @@ public interface RemoteSession {
Process exec(String commandName, int timeout) throws IOException;
/**
- * Obtain an {@link FtpChannel} for performing FTP operations over this
+ * Obtains an {@link FtpChannel} for performing FTP operations over this
* {@link RemoteSession}. The default implementation returns {@code null}.
*
* @return the {@link FtpChannel}
@@ -59,7 +53,7 @@ public interface RemoteSession {
}
/**
- * Disconnect the remote session
+ * Disconnects the remote session.
*/
void disconnect();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java
index b1fac2cffb..fff2938e5d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2018, 2020 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
@@ -117,6 +117,34 @@ public final class SshConstants {
/** Key in an ssh config file. */
public static final String PROXY_COMMAND = "ProxyCommand";
+ /**
+ * Comma-separated list of jump hosts, defining a jump host chain <em>in
+ * reverse order</em>. Each jump host is a SSH URI or "[user@]host[:port]".
+ * <p>
+ * Reverse order means: to connect A->B->target, one can do in
+ * {@code ~/.ssh/config} either of:
+ * </p>
+ *
+ * <pre>
+ * Host target
+ * ProxyJump B,A
+ * </pre>
+ * <p>
+ * <em>or</em>
+ * </p>
+ *
+ * <pre>
+ * Host target
+ * ProxyJump B
+ *
+ * Host B
+ * ProxyJump A
+ * </pre>
+ *
+ * @since 5.10
+ */
+ public static final String PROXY_JUMP = "ProxyJump";
+
/** Key in an ssh config file. */
public static final String REMOTE_COMMAND = "RemoteCommand";
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 ef845f4dce..e216a56ac6 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, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2020 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
@@ -27,12 +27,15 @@ import org.eclipse.jgit.util.SystemReader;
* Different implementations of the session factory may be used to control
* communicating with the end-user as well as reading their personal SSH
* configuration settings, such as known hosts and private keys.
+ * </p>
* <p>
- * A {@link org.eclipse.jgit.transport.RemoteSession} must be returned to the
- * factory that created it. Callers are encouraged to retain the
- * SshSessionFactory for the duration of the period they are using the Session.
+ * A {@link RemoteSession} must be returned to the factory that created it.
+ * Callers are encouraged to retain the SshSessionFactory for the duration of
+ * the period they are using the session.
+ * </p>
*/
public abstract class SshSessionFactory {
+
private static SshSessionFactory INSTANCE = loadSshSessionFactory();
private static SshSessionFactory loadSshSessionFactory() {
@@ -43,12 +46,13 @@ public abstract class SshSessionFactory {
}
return null;
}
-
+
/**
- * Get the currently configured JVM-wide factory.
+ * Gets the currently configured JVM-wide factory.
* <p>
- * By default the factory will read from the user's <code>$HOME/.ssh</code>
- * and assume OpenSSH compatibility.
+ * By default the factory will read from the user's {@code $HOME/.ssh} and
+ * assume OpenSSH compatibility.
+ * </p>
*
* @return factory the current factory for this JVM.
*/
@@ -57,11 +61,11 @@ public abstract class SshSessionFactory {
}
/**
- * Change the JVM-wide factory to a different implementation.
+ * Changes the JVM-wide factory to a different implementation.
*
* @param newFactory
- * factory for future sessions to be created through. If null the
- * default factory will be restored.
+ * factory for future sessions to be created through; if
+ * {@code null} the default factory will be restored.
*/
public static void setInstance(SshSessionFactory newFactory) {
if (newFactory != null) {
@@ -85,26 +89,23 @@ public abstract class SshSessionFactory {
}
/**
- * Open (or reuse) a session to a host.
- * <p>
- * A reasonable UserInfo that can interact with the end-user (if necessary)
- * is installed on the returned session by this method.
- * <p>
- * The caller must connect the session by invoking <code>connect()</code> if
- * it has not already been connected.
+ * Opens (or reuses) a session to a host. The returned session is connected
+ * and authenticated and is ready for further use.
*
* @param uri
- * URI information about the remote host
+ * URI of the remote host to connect to
* @param credentialsProvider
- * provider to support authentication, may be null.
+ * provider to support authentication, may be {@code null} if no
+ * user input for authentication is needed
* @param fs
- * the file system abstraction which will be necessary to perform
- * certain file system operations.
+ * the file system abstraction to use for certain file
+ * operations, such as reading configuration files
* @param tms
- * Timeout value, in milliseconds.
- * @return a session that can contact the remote host.
+ * connection timeout for creating the session, in milliseconds
+ * @return a connected and authenticated session for communicating with the
+ * remote host given by the {@code uri}
* @throws org.eclipse.jgit.errors.TransportException
- * the session could not be created.
+ * if the session could not be created
*/
public abstract RemoteSession getSession(URIish uri,
CredentialsProvider credentialsProvider, FS fs, int tms)
@@ -120,7 +121,7 @@ public abstract class SshSessionFactory {
public abstract String getType();
/**
- * Close (or recycle) a session to a host.
+ * Closes (or recycles) a session to a host.
*
* @param session
* a session previously obtained from this factory's
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 16169f028b..6768387e65 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -49,6 +49,7 @@ import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -900,7 +901,9 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP);
}
conn.setRequestProperty(HDR_PRAGMA, "no-cache"); //$NON-NLS-1$
- if (UserAgent.get() != null) {
+ if (http.getUserAgent() != null) {
+ conn.setRequestProperty(HDR_USER_AGENT, http.getUserAgent());
+ } else if (UserAgent.get() != null) {
conn.setRequestProperty(HDR_USER_AGENT, UserAgent.get());
}
int timeOut = getTimeout();
@@ -909,6 +912,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
conn.setConnectTimeout(effTimeOut);
conn.setReadTimeout(effTimeOut);
}
+ addHeaders(conn, http.getExtraHeaders());
// set cookie header if necessary
if (!relevantCookies.isEmpty()) {
setCookieHeader(conn);
@@ -923,6 +927,44 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
return conn;
}
+ /**
+ * Adds a list of header strings to the connection. Headers are expected to
+ * separate keys from values, i.e. "Key: Value". Headers without colon or
+ * key are ignored (and logged), as are headers with keys that are not RFC
+ * 7230 tokens or with non-ASCII values.
+ *
+ * @param conn
+ * The target HttpConnection
+ * @param headersToAdd
+ * A list of header strings
+ */
+ static void addHeaders(HttpConnection conn, List<String> headersToAdd) {
+ for (String header : headersToAdd) {
+ // Empty values are allowed according to
+ // https://tools.ietf.org/html/rfc7230
+ int colon = header.indexOf(':');
+ String key = null;
+ if (colon > 0) {
+ key = header.substring(0, colon).trim();
+ }
+ if (key == null || key.isEmpty()) {
+ LOG.warn(MessageFormat.format(
+ JGitText.get().invalidHeaderFormat, header));
+ } else if (HttpSupport.scanToken(key, 0) != key.length()) {
+ LOG.warn(MessageFormat.format(JGitText.get().invalidHeaderKey,
+ header));
+ } else {
+ String value = header.substring(colon + 1).trim();
+ if (!StandardCharsets.US_ASCII.newEncoder().canEncode(value)) {
+ LOG.warn(MessageFormat
+ .format(JGitText.get().invalidHeaderValue, header));
+ } else {
+ conn.setRequestProperty(key, value);
+ }
+ }
+ }
+ }
+
private void setCookieHeader(HttpConnection conn) {
StringBuilder cookieHeaderValue = new StringBuilder();
for (HttpCookie cookie : relevantCookies) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 9889015261..1242ef1b4a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -42,6 +42,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.text.MessageFormat;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -1008,7 +1010,7 @@ public class UploadPack {
else
advertised = refIdSet(getAdvertisedOrDefaultRefs().values());
- long negotiateStart = System.currentTimeMillis();
+ Instant negotiateStart = Instant.now();
accumulator.advertised = advertised.size();
ProtocolV0Parser parser = new ProtocolV0Parser(transferConfig);
@@ -1050,8 +1052,8 @@ public class UploadPack {
if (!req.getClientShallowCommits().isEmpty())
walk.assumeShallow(req.getClientShallowCommits());
sendPack = negotiate(req, accumulator, pckOut);
- accumulator.timeNegotiating += System.currentTimeMillis()
- - negotiateStart;
+ accumulator.timeNegotiating = Duration
+ .between(negotiateStart, Instant.now()).toMillis();
if (sendPack && !biDirectionalPipe) {
// Ensure the request was fully consumed. Any remaining input must
@@ -1137,6 +1139,9 @@ public class UploadPack {
advertised = refIdSet(getAdvertisedOrDefaultRefs().values());
}
+ PackStatistics.Accumulator accumulator = new PackStatistics.Accumulator();
+ Instant negotiateStart = Instant.now();
+
ProtocolV2Parser parser = new ProtocolV2Parser(transferConfig);
FetchV2Request req = parser.parseFetchRequest(pckIn);
currentRequest = req;
@@ -1186,7 +1191,8 @@ public class UploadPack {
if (req.wasDoneReceived()) {
processHaveLines(req.getPeerHas(), ObjectId.zeroId(),
- new PacketLineOut(NullOutputStream.INSTANCE));
+ new PacketLineOut(NullOutputStream.INSTANCE),
+ accumulator);
} else {
pckOut.writeString("acknowledgments\n"); //$NON-NLS-1$
for (ObjectId id : req.getPeerHas()) {
@@ -1195,7 +1201,8 @@ public class UploadPack {
}
}
processHaveLines(req.getPeerHas(), ObjectId.zeroId(),
- new PacketLineOut(NullOutputStream.INSTANCE));
+ new PacketLineOut(NullOutputStream.INSTANCE),
+ accumulator);
if (okToGiveUp()) {
pckOut.writeString("ready\n"); //$NON-NLS-1$
} else if (commonBase.isEmpty()) {
@@ -1238,7 +1245,11 @@ public class UploadPack {
// But sideband-all is not used, so we have to write it ourselves.
pckOut.writeString("packfile\n"); //$NON-NLS-1$
}
- sendPack(new PackStatistics.Accumulator(),
+
+ accumulator.timeNegotiating = Duration
+ .between(negotiateStart, Instant.now()).toMillis();
+
+ sendPack(accumulator,
req,
req.getClientCapabilities().contains(OPTION_INCLUDE_TAG)
? db.getRefDatabase().getRefsByPrefix(R_TAGS)
@@ -1641,7 +1652,7 @@ public class UploadPack {
}
if (PacketLineIn.isEnd(line)) {
- last = processHaveLines(peerHas, last, pckOut);
+ last = processHaveLines(peerHas, last, pckOut, accumulator);
if (commonBase.isEmpty() || multiAck != MultiAck.OFF)
pckOut.writeString("NAK\n"); //$NON-NLS-1$
if (noDone && sentReady) {
@@ -1656,7 +1667,7 @@ public class UploadPack {
peerHas.add(ObjectId.fromString(line.substring(5)));
accumulator.haves++;
} else if (line.equals("done")) { //$NON-NLS-1$
- last = processHaveLines(peerHas, last, pckOut);
+ last = processHaveLines(peerHas, last, pckOut, accumulator);
if (commonBase.isEmpty())
pckOut.writeString("NAK\n"); //$NON-NLS-1$
@@ -1672,11 +1683,12 @@ public class UploadPack {
}
}
- private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last, PacketLineOut out)
+ private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last,
+ PacketLineOut out, PackStatistics.Accumulator accumulator)
throws IOException {
preUploadHook.onBeginNegotiateRound(this, wantIds, peerHas.size());
if (wantAll.isEmpty() && !wantIds.isEmpty())
- parseWants();
+ parseWants(accumulator);
if (peerHas.isEmpty())
return last;
@@ -1773,7 +1785,7 @@ public class UploadPack {
return last;
}
- private void parseWants() throws IOException {
+ private void parseWants(PackStatistics.Accumulator accumulator) throws IOException {
List<ObjectId> notAdvertisedWants = null;
for (ObjectId obj : wantIds) {
if (!advertised.contains(obj)) {
@@ -1782,9 +1794,18 @@ public class UploadPack {
notAdvertisedWants.add(obj);
}
}
- if (notAdvertisedWants != null)
+ if (notAdvertisedWants != null) {
+ accumulator.notAdvertisedWants = notAdvertisedWants.size();
+
+ Instant startReachabilityChecking = Instant.now();
+
requestValidator.checkWants(this, notAdvertisedWants);
+ accumulator.reachabilityCheckDuration = Duration
+ .between(startReachabilityChecking, Instant.now())
+ .toMillis();
+ }
+
AsyncRevObjectQueue q = walk.parseAny(wantIds, true);
try {
RevObject obj;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java
index 5b63635e5a..604eb3a66c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java
@@ -46,7 +46,7 @@ public class UserAgent {
return "unknown"; //$NON-NLS-1$
}
- private static String clean(String s) {
+ static String clean(String s) {
s = s.trim();
StringBuilder b = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 994af2607c..72278dc9c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -2,7 +2,7 @@
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
* Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
- * Copyright (C) 2012-2013, Robin Rosenberg and others
+ * Copyright (C) 2012-2020, Robin Rosenberg and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -25,6 +25,7 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetEncoder;
+import java.nio.file.Path;
import java.text.MessageFormat;
import java.time.Instant;
import java.util.Arrays;
@@ -48,8 +49,8 @@ import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.ignore.FastIgnoreRule;
import org.eclipse.jgit.ignore.IgnoreNode;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.CoreConfig;
import org.eclipse.jgit.lib.CoreConfig.CheckStat;
import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.CoreConfig.SymLinks;
@@ -522,6 +523,17 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
return state.options;
}
+ /**
+ * Retrieves the {@link Repository} this {@link WorkingTreeIterator}
+ * operates on.
+ *
+ * @return the {@link Repository}
+ * @since 5.9
+ */
+ public Repository getRepository() {
+ return repository;
+ }
+
/** {@inheritDoc} */
@Override
public int idOffset() {
@@ -1297,15 +1309,11 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
FS fs = repository.getFS();
- String path = repository.getConfig().get(CoreConfig.KEY)
- .getExcludesFile();
+ Path path = repository.getConfig().getPath(
+ ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_EXCLUDESFILE, fs, null, null);
if (path != null) {
- File excludesfile;
- if (path.startsWith("~/")) //$NON-NLS-1$
- excludesfile = fs.resolve(fs.userHome(), path.substring(2));
- else
- excludesfile = fs.resolve(null, path);
- loadRulesFromFile(r, excludesfile);
+ loadRulesFromFile(r, path.toFile());
}
File exclude = fs.resolve(repository.getDirectory(),
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
index 19cda42485..4731f345bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java
@@ -217,14 +217,15 @@ public class IndexDiffFilter extends TreeFilter {
*/
private void copyUntrackedFolders(String currentPath) {
String pathToBeSaved = null;
- while (!untrackedParentFolders.isEmpty()
- && !currentPath.startsWith(untrackedParentFolders.getFirst()
- + "/")) //$NON-NLS-1$
+ while (!untrackedParentFolders.isEmpty() && !currentPath
+ .startsWith(untrackedParentFolders.getFirst() + '/')) {
pathToBeSaved = untrackedParentFolders.removeFirst();
+ }
if (pathToBeSaved != null) {
- while (!untrackedFolders.isEmpty()
- && untrackedFolders.getLast().startsWith(pathToBeSaved))
+ while (!untrackedFolders.isEmpty() && untrackedFolders.getLast()
+ .startsWith(pathToBeSaved + '/')) {
untrackedFolders.removeLast();
+ }
untrackedFolders.addLast(pathToBeSaved);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 91574efec4..d8cab358e7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -52,7 +52,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -186,12 +186,18 @@ public abstract class FS {
*/
public static final class FileStoreAttributes {
+ /**
+ * Marker to detect undefined values when reading from the config file.
+ */
private static final Duration UNDEFINED_DURATION = Duration
.ofNanos(Long.MAX_VALUE);
/**
* Fallback filesystem timestamp resolution. The worst case timestamp
* resolution on FAT filesystems is 2 seconds.
+ * <p>
+ * Must be at least 1 second.
+ * </p>
*/
public static final Duration FALLBACK_TIMESTAMP_RESOLUTION = Duration
.ofMillis(2000);
@@ -204,6 +210,25 @@ public abstract class FS {
public static final FileStoreAttributes FALLBACK_FILESTORE_ATTRIBUTES = new FileStoreAttributes(
FALLBACK_TIMESTAMP_RESOLUTION);
+ private static final long ONE_MICROSECOND = TimeUnit.MICROSECONDS
+ .toNanos(1);
+
+ private static final long ONE_MILLISECOND = TimeUnit.MILLISECONDS
+ .toNanos(1);
+
+ private static final long ONE_SECOND = TimeUnit.SECONDS.toNanos(1);
+
+ /**
+ * Minimum file system timestamp resolution granularity to check, in
+ * nanoseconds. Should be a positive power of ten smaller than
+ * {@link #ONE_SECOND}. Must be strictly greater than zero, i.e.,
+ * minimum value is 1 nanosecond.
+ * <p>
+ * Currently set to 1 microsecond, but could also be lower still.
+ * </p>
+ */
+ private static final long MINIMUM_RESOLUTION_NANOS = ONE_MICROSECOND;
+
private static final String JAVA_VERSION_PREFIX = System
.getProperty("java.vendor") + '|' //$NON-NLS-1$
+ System.getProperty("java.version") + '|'; //$NON-NLS-1$
@@ -235,9 +260,10 @@ public abstract class FS {
* @see java.util.concurrent.Executors#newCachedThreadPool()
*/
private static final Executor FUTURE_RUNNER = new ThreadPoolExecutor(0,
- 5, 30L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
+ 5, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
runnable -> {
- Thread t = new Thread(runnable, "FileStoreAttributeReader-" //$NON-NLS-1$
+ Thread t = new Thread(runnable,
+ "JGit-FileStoreAttributeReader-" //$NON-NLS-1$
+ threadNumber.getAndIncrement());
// Make sure these threads don't prevent application/JVM
// shutdown.
@@ -246,12 +272,34 @@ public abstract class FS {
});
/**
+ * Use a separate executor with at most one thread to synchronize
+ * writing to the config. We write asynchronously since the config
+ * itself might be on a different file system, which might otherwise
+ * lead to locking problems.
+ * <p>
+ * Writing the config must not use a daemon thread, otherwise we may
+ * leave an inconsistent state on disk when the JVM shuts down. Use a
+ * small keep-alive time to avoid delays on shut-down.
+ * </p>
+ */
+ private static final Executor SAVE_RUNNER = new ThreadPoolExecutor(0, 1,
+ 1L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
+ runnable -> {
+ Thread t = new Thread(runnable,
+ "JGit-FileStoreAttributeWriter-" //$NON-NLS-1$
+ + threadNumber.getAndIncrement());
+ // Make sure these threads do finish
+ t.setDaemon(false);
+ return t;
+ });
+
+ /**
* Whether FileStore attributes should be determined asynchronously
*
* @param async
* whether FileStore attributes should be determined
- * asynchronously. If false access to cached attributes may block
- * for some seconds for the first call per FileStore
+ * asynchronously. If false access to cached attributes may
+ * block for some seconds for the first call per FileStore
* @since 5.6.2
*/
public static void setBackground(boolean async) {
@@ -294,6 +342,10 @@ public abstract class FS {
return cached;
}
FileStoreAttributes attrs = getFileStoreAttributes(dir);
+ if (attrs == null) {
+ // Don't cache, result might be late
+ return FALLBACK_FILESTORE_ATTRIBUTES;
+ }
attrCacheByPath.put(dir, attrs);
return attrs;
} catch (SecurityException e) {
@@ -367,7 +419,9 @@ public abstract class FS {
if (LOG.isDebugEnabled()) {
LOG.debug(c.toString());
}
- saveToConfig(s, c);
+ FileStoreAttributes newAttrs = c;
+ SAVE_RUNNER.execute(
+ () -> saveToConfig(s, newAttrs));
}
attributes = Optional.of(c);
} finally {
@@ -382,12 +436,16 @@ public abstract class FS {
});
// even if measuring in background wait a little - if the result
// arrives, it's better than returning the large fallback
- Optional<FileStoreAttributes> d = background.get() ? f.get(
+ boolean runInBackground = background.get();
+ Optional<FileStoreAttributes> d = runInBackground ? f.get(
100, TimeUnit.MILLISECONDS) : f.get();
if (d.isPresent()) {
return d.get();
+ } else if (runInBackground) {
+ // return null until measurement is finished
+ return null;
}
- // return fallback until measurement is finished
+ // fall through and return fallback
} catch (IOException | InterruptedException
| ExecutionException | CancellationException e) {
LOG.error(e.getMessage(), e);
@@ -467,24 +525,21 @@ public abstract class FS {
private static Optional<Duration> measureFsTimestampResolution(
FileStore s, Path dir) {
- LOG.debug("{}: start measure timestamp resolution {} in {}", //$NON-NLS-1$
- Thread.currentThread(), s, dir);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("{}: start measure timestamp resolution {} in {}", //$NON-NLS-1$
+ Thread.currentThread(), s, dir);
+ }
Path probe = dir.resolve(".probe-" + UUID.randomUUID()); //$NON-NLS-1$
try {
Files.createFile(probe);
- FileTime t1 = Files.getLastModifiedTime(probe);
- FileTime t2 = t1;
- Instant t1i = t1.toInstant();
- for (long i = 1; t2.compareTo(t1) <= 0; i += 1 + i / 20) {
- Files.setLastModifiedTime(probe,
- FileTime.from(t1i.plusNanos(i * 1000)));
- t2 = Files.getLastModifiedTime(probe);
- }
- Duration fsResolution = Duration.between(t1.toInstant(), t2.toInstant());
+ Duration fsResolution = getFsResolution(s, dir, probe);
Duration clockResolution = measureClockResolution();
fsResolution = fsResolution.plus(clockResolution);
- LOG.debug("{}: end measure timestamp resolution {} in {}", //$NON-NLS-1$
- Thread.currentThread(), s, dir);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "{}: end measure timestamp resolution {} in {}; got {}", //$NON-NLS-1$
+ Thread.currentThread(), s, dir, fsResolution);
+ }
return Optional.of(fsResolution);
} catch (SecurityException e) {
// Log it here; most likely deleteProbe() below will also run
@@ -501,6 +556,92 @@ public abstract class FS {
return Optional.empty();
}
+ private static Duration getFsResolution(FileStore s, Path dir,
+ Path probe) throws IOException {
+ File probeFile = probe.toFile();
+ FileTime t1 = Files.getLastModifiedTime(probe);
+ Instant t1i = t1.toInstant();
+ FileTime t2;
+ Duration last = FALLBACK_TIMESTAMP_RESOLUTION;
+ long minScale = MINIMUM_RESOLUTION_NANOS;
+ long scale = ONE_SECOND;
+ long high = TimeUnit.MILLISECONDS.toSeconds(last.toMillis());
+ long low = 0;
+ // Try up-front at microsecond and millisecond
+ long[] tries = { ONE_MICROSECOND, ONE_MILLISECOND };
+ for (long interval : tries) {
+ if (interval >= ONE_MILLISECOND) {
+ probeFile.setLastModified(
+ t1i.plusNanos(interval).toEpochMilli());
+ } else {
+ Files.setLastModifiedTime(probe,
+ FileTime.from(t1i.plusNanos(interval)));
+ }
+ t2 = Files.getLastModifiedTime(probe);
+ if (t2.compareTo(t1) > 0) {
+ Duration diff = Duration.between(t1i, t2.toInstant());
+ if (!diff.isZero() && !diff.isNegative()
+ && diff.compareTo(last) < 0) {
+ scale = interval;
+ high = 1;
+ last = diff;
+ break;
+ }
+ } else {
+ // Makes no sense going below
+ minScale = Math.max(minScale, interval);
+ }
+ }
+ // Binary search loop
+ while (high > low) {
+ long mid = (high + low) / 2;
+ if (mid == 0) {
+ // Smaller than current scale. Adjust scale.
+ long newScale = scale / 10;
+ if (newScale < minScale) {
+ break;
+ }
+ high *= scale / newScale;
+ low *= scale / newScale;
+ scale = newScale;
+ mid = (high + low) / 2;
+ }
+ long delta = mid * scale;
+ if (scale >= ONE_MILLISECOND) {
+ probeFile.setLastModified(
+ t1i.plusNanos(delta).toEpochMilli());
+ } else {
+ Files.setLastModifiedTime(probe,
+ FileTime.from(t1i.plusNanos(delta)));
+ }
+ t2 = Files.getLastModifiedTime(probe);
+ int cmp = t2.compareTo(t1);
+ if (cmp > 0) {
+ high = mid;
+ Duration diff = Duration.between(t1i, t2.toInstant());
+ if (diff.isZero() || diff.isNegative()) {
+ LOG.warn(JGitText.get().logInconsistentFiletimeDiff,
+ Thread.currentThread(), s, dir, t2, t1, diff,
+ last);
+ break;
+ } else if (diff.compareTo(last) > 0) {
+ LOG.warn(JGitText.get().logLargerFiletimeDiff,
+ Thread.currentThread(), s, dir, diff, last);
+ break;
+ }
+ last = diff;
+ } else if (cmp < 0) {
+ LOG.warn(JGitText.get().logSmallerFiletime,
+ Thread.currentThread(), s, dir, t2, t1, last);
+ break;
+ } else {
+ // No discernible difference
+ low = mid + 1;
+ }
+ }
+ return last;
+ }
+
private static Duration measureClockResolution() {
Duration clockResolution = Duration.ZERO;
for (int i = 0; i < 10; i++) {
@@ -939,8 +1080,9 @@ public abstract class FS {
}
/**
- * Set the last modified time of a file system object. If the OS/JRE support
- * symbolic links, the link is modified, not the target,
+ * Set the last modified time of a file system object.
+ * <p>
+ * For symlinks it sets the modified time of the link target.
*
* @param f
* a {@link java.io.File} object.
@@ -956,8 +1098,9 @@ public abstract class FS {
}
/**
- * Set the last modified time of a file system object. If the OS/JRE support
- * symbolic links, the link is modified, not the target,
+ * Set the last modified time of a file system object.
+ * <p>
+ * For symlinks it sets the modified time of the link target.
*
* @param p
* a {@link Path} object.
@@ -1356,7 +1499,7 @@ public abstract class FS {
String v;
try {
v = readPipe(gitExe.getParentFile(),
- new String[] { "git", "--version" }, //$NON-NLS-1$ //$NON-NLS-2$
+ new String[] { gitExe.getPath(), "--version" }, //$NON-NLS-1$
Charset.defaultCharset().name());
} catch (CommandFailedException e) {
LOG.warn(e.getMessage());
@@ -1375,7 +1518,8 @@ public abstract class FS {
String w;
try {
w = readPipe(gitExe.getParentFile(),
- new String[] { "git", "config", "--system", "--edit" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ new String[] { gitExe.getPath(), "config", "--system", //$NON-NLS-1$ //$NON-NLS-2$
+ "--edit" }, //$NON-NLS-1$
Charset.defaultCharset().name(), env);
} catch (CommandFailedException e) {
LOG.warn(e.getMessage());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
index c9d2770b18..fb63dc02bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
@@ -54,6 +54,8 @@ import org.slf4j.LoggerFactory;
public class FS_POSIX extends FS {
private static final Logger LOG = LoggerFactory.getLogger(FS_POSIX.class);
+ private static final String DEFAULT_GIT_LOCATION = "/usr/bin/git"; //$NON-NLS-1$
+
private static final int DEFAULT_UMASK = 0022;
private volatile int umask = -1;
@@ -138,24 +140,46 @@ public class FS_POSIX extends FS {
String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
File gitExe = searchPath(path, "git"); //$NON-NLS-1$
- if (gitExe == null) {
- if (SystemReader.getInstance().isMacOS()) {
+ if (SystemReader.getInstance().isMacOS()) {
+ if (gitExe == null
+ || DEFAULT_GIT_LOCATION.equals(gitExe.getPath())) {
if (searchPath(path, "bash") != null) { //$NON-NLS-1$
// On MacOSX, PATH is shorter when Eclipse is launched from the
// Finder than from a terminal. Therefore try to launch bash as a
// login shell and search using that.
- String w;
try {
- w = readPipe(userHome(),
+ String w = readPipe(userHome(),
new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Charset.defaultCharset().name());
+ if (!StringUtils.isEmptyOrNull(w)) {
+ gitExe = new File(w);
+ }
} catch (CommandFailedException e) {
LOG.warn(e.getMessage());
- return null;
}
- if (!StringUtils.isEmptyOrNull(w)) {
- gitExe = new File(w);
+ }
+ }
+ if (gitExe != null
+ && DEFAULT_GIT_LOCATION.equals(gitExe.getPath())) {
+ // If we still have the default git exe, it's an XCode wrapper
+ // that may prompt the user to install the XCode command line
+ // tools if not already present. Avoid the prompt by returning
+ // null if no XCode git is there.
+ try {
+ String w = readPipe(userHome(),
+ new String[] { "xcode-select", "-p" }, //$NON-NLS-1$ //$NON-NLS-2$
+ Charset.defaultCharset().name());
+ if (StringUtils.isEmptyOrNull(w)) {
+ gitExe = null;
+ } else {
+ File realGitExe = new File(new File(w),
+ DEFAULT_GIT_LOCATION.substring(1));
+ if (!realGitExe.exists()) {
+ gitExe = null;
+ }
}
+ } catch (CommandFailedException e) {
+ gitExe = null;
}
}
}
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 c43956e53d..aa39a44642 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -710,6 +710,8 @@ public class FileUtils {
}
/**
+ * Set the last modified time of a file system object.
+ *
* @param file
* @param time
* @throws IOException
@@ -720,6 +722,8 @@ public class FileUtils {
}
/**
+ * Set the last modified time of a file system object.
+ *
* @param path
* @param time
* @throws IOException
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
index 8ff649bccc..04b3eab504 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java
@@ -424,6 +424,69 @@ public class HttpSupport {
}
}
+ /**
+ * Scan a RFC 7230 token as it appears in HTTP headers.
+ *
+ * @param header
+ * to scan in
+ * @param from
+ * index in {@code header} to start scanning at
+ * @return the index after the token, that is, on the first non-token
+ * character or {@code header.length}
+ * @throws IndexOutOfBoundsException
+ * if {@code from < 0} or {@code from > header.length()}
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc7230#appendix-B">RFC 7230,
+ * Appendix B: Collected Grammar; "token" production</a>
+ * @since 5.10
+ */
+ public static int scanToken(String header, int from) {
+ int length = header.length();
+ int i = from;
+ if (i < 0 || i > length) {
+ throw new IndexOutOfBoundsException();
+ }
+ while (i < length) {
+ char c = header.charAt(i);
+ switch (c) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i++;
+ break;
+ default:
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ i++;
+ break;
+ }
+ return i;
+ }
+ }
+ return i;
+ }
+
private HttpSupport() {
// Utility class only.
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
index a151cd336f..e29704158d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SshSupport.java
@@ -11,6 +11,7 @@ package org.eclipse.jgit.util;
import java.io.IOException;
import java.text.MessageFormat;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.CommandFailedException;
@@ -61,11 +62,21 @@ public class SshSupport {
CommandFailedException failure = null;
@SuppressWarnings("resource")
MessageWriter stderr = new MessageWriter();
+ @SuppressWarnings("resource")
+ MessageWriter stdout = new MessageWriter();
String out;
- try (MessageWriter stdout = new MessageWriter()) {
+ try {
+ long start = System.nanoTime();
session = SshSessionFactory.getInstance().getSession(sshUri,
provider, fs, 1000 * timeout);
- process = session.exec(command, 0);
+ int commandTimeout = timeout;
+ if (timeout > 0) {
+ commandTimeout = checkTimeout(command, timeout, start);
+ }
+ process = session.exec(command, commandTimeout);
+ if (timeout > 0) {
+ commandTimeout = checkTimeout(command, timeout, start);
+ }
errorThread = new StreamCopyThread(process.getErrorStream(),
stderr.getRawStream());
errorThread.start();
@@ -73,9 +84,15 @@ public class SshSupport {
stdout.getRawStream());
outThread.start();
try {
- // waitFor with timeout has a bug - JSch' exitValue() throws the
- // wrong exception type :(
- if (process.waitFor() == 0) {
+ boolean finished = false;
+ if (timeout <= 0) {
+ process.waitFor();
+ finished = true;
+ } else {
+ finished = process.waitFor(commandTimeout,
+ TimeUnit.SECONDS);
+ }
+ if (finished) {
out = stdout.toString();
} else {
out = null; // still running after timeout
@@ -103,15 +120,26 @@ public class SshSupport {
}
}
if (process != null) {
- if (process.exitValue() != 0) {
- failure = new CommandFailedException(process.exitValue(),
+ try {
+ if (process.exitValue() != 0) {
+ failure = new CommandFailedException(
+ process.exitValue(),
+ MessageFormat.format(
+ JGitText.get().sshCommandFailed,
+ command, stderr.toString()));
+ }
+ // It was successful after all
+ out = stdout.toString();
+ } catch (IllegalThreadStateException e) {
+ failure = new CommandFailedException(0,
MessageFormat.format(
- JGitText.get().sshCommandFailed, command,
- stderr.toString()));
+ JGitText.get().sshCommandTimeout, command,
+ Integer.valueOf(timeout)));
}
process.destroy();
}
stderr.close();
+ stdout.close();
if (session != null) {
SshSessionFactory.getInstance().releaseSession(session);
}
@@ -122,4 +150,17 @@ public class SshSupport {
return out;
}
+ private static int checkTimeout(String command, int timeout, long since)
+ throws CommandFailedException {
+ long elapsed = System.nanoTime() - since;
+ int newTimeout = timeout
+ - (int) TimeUnit.NANOSECONDS.toSeconds(elapsed);
+ if (newTimeout <= 0) {
+ // All time used up for connecting the session
+ throw new CommandFailedException(0,
+ MessageFormat.format(JGitText.get().sshCommandTimeout,
+ command, Integer.valueOf(timeout)));
+ }
+ return newTimeout;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index bcb8380625..447f417e7e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -17,7 +17,6 @@ import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -116,11 +115,9 @@ public abstract class SystemReader {
.getAbsolutePath();
}
try {
- Path xdgHomePath = Paths.get(configHomePath);
- Files.createDirectories(xdgHomePath);
- return xdgHomePath;
- } catch (IOException | InvalidPathException e) {
- LOG.error(JGitText.get().createXDGConfigHomeFailed,
+ return Paths.get(configHomePath);
+ } catch (InvalidPathException e) {
+ LOG.error(JGitText.get().logXDGConfigHomeInvalid,
configHomePath, e);
}
return null;
@@ -130,16 +127,9 @@ public abstract class SystemReader {
public FileBasedConfig openJGitConfig(Config parent, FS fs) {
Path xdgPath = getXDGConfigHome(fs);
if (xdgPath != null) {
- Path configPath = null;
- try {
- configPath = xdgPath.resolve("jgit"); //$NON-NLS-1$
- Files.createDirectories(configPath);
- configPath = configPath.resolve(Constants.CONFIG);
- return new FileBasedConfig(parent, configPath.toFile(), fs);
- } catch (IOException e) {
- LOG.error(JGitText.get().createJGitConfigFailed, configPath,
- e);
- }
+ Path configPath = xdgPath.resolve("jgit") //$NON-NLS-1$
+ .resolve(Constants.CONFIG);
+ return new FileBasedConfig(parent, configPath.toFile(), fs);
}
return new FileBasedConfig(parent,
new File(fs.userHome(), ".jgitconfig"), fs); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
index 8c9b1bf5cc..0e335a9dc4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFInputStream.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010, 2013 Marc Strapetz <marc.strapetz@syntevo.com>
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> and others
+ * Copyright (C) 2015, 2020 Ivan Motsch <ivan.motsch@bsiag.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -13,26 +13,58 @@ package org.eclipse.jgit.util.io;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Set;
import org.eclipse.jgit.diff.RawText;
/**
* An InputStream that normalizes CRLF to LF.
- *
- * Existing single CR are not changed to LF, but retained as is.
- *
- * Optionally, a binary check on the first 8000 bytes is performed and in case
- * of binary files, canonicalization is turned off (for the complete file).
* <p>
- * This is the former EolCanonicalizingInputStream with a new name in order to
- * have same naming for all LF / CRLF streams
+ * Existing single CR are not changed to LF but are retained as is.
+ * </p>
+ * <p>
+ * Optionally, a binary check on the first 8kB is performed and in case of
+ * binary files, canonicalization is turned off (for the complete file). If
+ * binary checking determines that the input is CR/LF-delimited text and the
+ * stream has been created for checkout, canonicalization is also turned off.
+ * </p>
*
* @since 4.3
*/
public class AutoLFInputStream extends InputStream {
+
+ // This is the former EolCanonicalizingInputStream with a new name in order
+ // to have same naming for all LF / CRLF streams.
+
+ /**
+ * Flags for controlling auto-detection of binary vs. text content (for
+ * text=auto).
+ *
+ * @since 5.9
+ */
+ public enum StreamFlag {
+ /**
+ * Check the first 8kB for binary content and switch off
+ * canonicalization off for the whole file if so.
+ */
+ DETECT_BINARY,
+ /**
+ * If {@link #DETECT_BINARY} is set, throw an {@link IsBinaryException}
+ * if binary content is detected.
+ */
+ ABORT_IF_BINARY,
+ /**
+ * If {@link #DETECT_BINARY} is set and content is found to be CR-LF
+ * delimited text, switch off canonicalization.
+ */
+ FOR_CHECKOUT
+ }
+
private final byte[] single = new byte[1];
- private final byte[] buf = new byte[8096];
+ private final byte[] buf = new byte[8 * 1024];
private final InputStream in;
@@ -40,11 +72,23 @@ public class AutoLFInputStream extends InputStream {
private int ptr;
+ /**
+ * Set to {@code true} if no CR/LF processing is to be done: if the input is
+ * binary data, or CR/LF-delimited text and {@link StreamFlag#FOR_CHECKOUT}
+ * was given.
+ */
+ private boolean passAsIs;
+
+ /**
+ * Set to {@code true} if the input was detected to be binary data.
+ */
private boolean isBinary;
private boolean detectBinary;
- private boolean abortIfBinary;
+ private final boolean abortIfBinary;
+
+ private final boolean forCheckout;
/**
* A special exception thrown when {@link AutoLFInputStream} is told to
@@ -62,20 +106,64 @@ public class AutoLFInputStream extends InputStream {
}
/**
- * Creates a new InputStream, wrapping the specified stream
+ * Factory method for creating an {@link AutoLFInputStream} with the
+ * specified {@link StreamFlag flags}.
+ *
+ * @param in
+ * raw input stream
+ * @param flags
+ * {@link StreamFlag}s controlling the stream behavior
+ * @return a new {@link AutoLFInputStream}
+ * @since 5.9
+ */
+ public static AutoLFInputStream create(InputStream in,
+ StreamFlag... flags) {
+ if (flags == null) {
+ return new AutoLFInputStream(in, null);
+ }
+ EnumSet<StreamFlag> set = EnumSet.noneOf(StreamFlag.class);
+ set.addAll(Arrays.asList(flags));
+ return new AutoLFInputStream(in, set);
+ }
+
+ /**
+ * Creates a new InputStream, wrapping the specified stream.
+ *
+ * @param in
+ * raw input stream
+ * @param flags
+ * {@link StreamFlag}s controlling the stream behavior;
+ * {@code null} is treated as an empty set
+ * @since 5.9
+ */
+ public AutoLFInputStream(InputStream in, Set<StreamFlag> flags) {
+ this.in = in;
+ this.detectBinary = flags != null
+ && flags.contains(StreamFlag.DETECT_BINARY);
+ this.abortIfBinary = flags != null
+ && flags.contains(StreamFlag.ABORT_IF_BINARY);
+ this.forCheckout = flags != null
+ && flags.contains(StreamFlag.FOR_CHECKOUT);
+ }
+
+ /**
+ * Creates a new InputStream, wrapping the specified stream.
*
* @param in
* raw input stream
* @param detectBinary
* whether binaries should be detected
* @since 2.0
+ * @deprecated since 5.9, use {@link #create(InputStream, StreamFlag...)}
+ * instead
*/
+ @Deprecated
public AutoLFInputStream(InputStream in, boolean detectBinary) {
this(in, detectBinary, false);
}
/**
- * Creates a new InputStream, wrapping the specified stream
+ * Creates a new InputStream, wrapping the specified stream.
*
* @param in
* raw input stream
@@ -84,12 +172,16 @@ public class AutoLFInputStream extends InputStream {
* @param abortIfBinary
* throw an IOException if the file is binary
* @since 3.3
+ * @deprecated since 5.9, use {@link #create(InputStream, StreamFlag...)}
+ * instead
*/
+ @Deprecated
public AutoLFInputStream(InputStream in, boolean detectBinary,
boolean abortIfBinary) {
this.in = in;
this.detectBinary = detectBinary;
this.abortIfBinary = abortIfBinary;
+ this.forCheckout = false;
}
/** {@inheritDoc} */
@@ -118,7 +210,7 @@ public class AutoLFInputStream extends InputStream {
}
byte b = buf[ptr++];
- if (isBinary || b != '\r') {
+ if (passAsIs || b != '\r') {
// Logic for binary files ends here
bs[i++] = b;
continue;
@@ -170,9 +262,14 @@ public class AutoLFInputStream extends InputStream {
}
if (detectBinary) {
isBinary = RawText.isBinary(buf, cnt);
+ passAsIs = isBinary;
detectBinary = false;
- if (isBinary && abortIfBinary)
+ if (isBinary && abortIfBinary) {
throw new IsBinaryException();
+ }
+ if (!passAsIs && forCheckout) {
+ passAsIs = RawText.isCrLfText(buf, cnt);
+ }
}
ptr = 0;
return true;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
index e235aa0ed4..195fdb4213 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/AutoLFOutputStream.java
@@ -1,43 +1,12 @@
/*
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ * Copyright (C) 2020, 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 v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
*
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.util.io;
@@ -49,11 +18,15 @@ import org.eclipse.jgit.diff.RawText;
/**
* An OutputStream that reduces CRLF to LF.
- *
+ * <p>
* Existing single CR are not changed to LF, but retained as is.
- *
+ * </p>
+ * <p>
* A binary check on the first 8000 bytes is performed and in case of binary
- * files, canonicalization is turned off (for the complete file).
+ * files, canonicalization is turned off (for the complete file). If the binary
+ * check determines that the input is not binary but text with CR/LF,
+ * canonicalization is also turned off.
+ * </p>
*
* @since 4.3
*/
@@ -76,9 +49,7 @@ public class AutoLFOutputStream extends OutputStream {
private boolean isBinary;
/**
- * <p>
* Constructor for AutoLFOutputStream.
- * </p>
*
* @param out
* an {@link java.io.OutputStream} object.
@@ -88,9 +59,7 @@ public class AutoLFOutputStream extends OutputStream {
}
/**
- * <p>
* Constructor for AutoLFOutputStream.
- * </p>
*
* @param out
* an {@link java.io.OutputStream} object.
@@ -123,14 +92,11 @@ public class AutoLFOutputStream extends OutputStream {
public void write(byte[] b, int startOff, int startLen)
throws IOException {
final int overflow = buffer(b, startOff, startLen);
- if (overflow < 0) {
+ if (overflow <= 0) {
return;
}
final int off = startOff + startLen - overflow;
final int len = overflow;
- if (len == 0) {
- return;
- }
int lastw = off;
if (isBinary) {
out.write(b, off, len);
@@ -190,6 +156,9 @@ public class AutoLFOutputStream extends OutputStream {
private void decideMode() throws IOException {
if (detectBinary) {
isBinary = RawText.isBinary(binbuf, binbufcnt);
+ if (!isBinary) {
+ isBinary = RawText.isCrLfText(binbuf, binbufcnt);
+ }
detectBinary = false;
}
int cachedLen = binbufcnt;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
index c33c869b64..88ee2aee88 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/EolStreamTypeUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> and others
+ * Copyright (C) 2015, 2020 Ivan Motsch <ivan.motsch@bsiag.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -12,12 +12,14 @@ package org.eclipse.jgit.util.io;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.EnumSet;
import org.eclipse.jgit.attributes.Attributes;
import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.WorkingTreeOptions;
import org.eclipse.jgit.util.SystemReader;
+import org.eclipse.jgit.util.io.AutoLFInputStream.StreamFlag;
/**
* Utility used to create input and output stream wrappers for
@@ -71,7 +73,7 @@ public final class EolStreamTypeUtil {
/**
* Wrap the input stream depending on
- * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
+ * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}.
*
* @param in
* original stream
@@ -82,15 +84,38 @@ public final class EolStreamTypeUtil {
*/
public static InputStream wrapInputStream(InputStream in,
EolStreamType conversion) {
+ return wrapInputStream(in, conversion, false);
+ }
+
+ /**
+ * Wrap the input stream depending on
+ * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}.
+ *
+ * @param in
+ * original stream
+ * @param conversion
+ * to be performed
+ * @param forCheckout
+ * whether the stream is for checking out from the repository
+ * @return the converted stream depending on
+ * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
+ * @since 5.9
+ */
+ public static InputStream wrapInputStream(InputStream in,
+ EolStreamType conversion, boolean forCheckout) {
switch (conversion) {
case TEXT_CRLF:
return new AutoCRLFInputStream(in, false);
case TEXT_LF:
- return new AutoLFInputStream(in, false);
+ return AutoLFInputStream.create(in);
case AUTO_CRLF:
return new AutoCRLFInputStream(in, true);
case AUTO_LF:
- return new AutoLFInputStream(in, true);
+ EnumSet<StreamFlag> flags = forCheckout
+ ? EnumSet.of(StreamFlag.DETECT_BINARY,
+ StreamFlag.FOR_CHECKOUT)
+ : EnumSet.of(StreamFlag.DETECT_BINARY);
+ return new AutoLFInputStream(in, flags);
default:
return in;
}
@@ -98,7 +123,7 @@ public final class EolStreamTypeUtil {
/**
* Wrap the output stream depending on
- * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
+ * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}.
*
* @param out
* original stream
diff --git a/pom.xml b/pom.xml
index a714f23912..cf581feed7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,13 +33,13 @@
</description>
<scm>
- <url>http://git.eclipse.org/c/jgit/jgit.git/</url>
+ <url>https://git.eclipse.org/r/plugins/gitiles/jgit/jgit</url>
<connection>scm:git:https://git.eclipse.org/r/jgit/jgit</connection>
</scm>
<ciManagement>
- <system>hudson</system>
- <url>https://hudson.eclipse.org/jgit/</url>
+ <system>Jenkins</system>
+ <url>https://ci.eclipse.org/jgit</url>
</ciManagement>
<developers>
@@ -140,7 +140,7 @@
</licenses>
<properties>
- <jgit-url>http://www.eclipse.org/jgit/</jgit-url>
+ <jgit-url>https://www.eclipse.org/jgit/</jgit-url>
<jgit-copyright>Copyright (c) 2005, 2009 Shawn Pearce, Robin Rosenberg, et.al.</jgit-copyright>
<jgit.website.url>scp://build.eclipse.org/home/data/httpd/download.eclipse.org/jgit/site/${project.version}/</jgit.website.url>
@@ -151,7 +151,7 @@
<maven.compiler.target>1.8</maven.compiler.target>
<bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
- <jgit-last-release-version>5.7.0.202003110725-r</jgit-last-release-version>
+ <jgit-last-release-version>5.9.0.202009080501-r</jgit-last-release-version>
<apache-sshd-version>2.4.0</apache-sshd-version>
<jsch-version>0.1.55</jsch-version>
<jzlib-version>1.1.1</jzlib-version>
@@ -162,22 +162,23 @@
<commons-compress-version>1.19</commons-compress-version>
<osgi-core-version>4.3.1</osgi-core-version>
<servlet-api-version>3.1.0</servlet-api-version>
- <jetty-version>9.4.28.v20200408</jetty-version>
+ <jetty-version>9.4.30.v20200611</jetty-version>
<japicmp-version>0.14.3</japicmp-version>
<httpclient-version>4.5.10</httpclient-version>
<httpcore-version>4.4.12</httpcore-version>
- <slf4j-version>1.7.2</slf4j-version>
+ <slf4j-version>1.7.30</slf4j-version>
<log4j-version>1.2.15</log4j-version>
<maven-javadoc-plugin-version>3.2.0</maven-javadoc-plugin-version>
<tycho-extras-version>1.7.0</tycho-extras-version>
<gson-version>2.8.2</gson-version>
<bouncycastle-version>1.65</bouncycastle-version>
- <spotbugs-maven-plugin-version>4.0.0</spotbugs-maven-plugin-version>
- <maven-project-info-reports-plugin-version>3.1.0</maven-project-info-reports-plugin-version>
+ <spotbugs-maven-plugin-version>4.1.3</spotbugs-maven-plugin-version>
+ <maven-project-info-reports-plugin-version>3.1.1</maven-project-info-reports-plugin-version>
<maven-jxr-plugin-version>3.0.0</maven-jxr-plugin-version>
<maven-surefire-plugin-version>3.0.0-M4</maven-surefire-plugin-version>
<maven-surefire-report-plugin-version>${maven-surefire-plugin-version}</maven-surefire-report-plugin-version>
<maven-compiler-plugin-version>3.8.1</maven-compiler-plugin-version>
+ <plexus-compiler-version>2.8.8</plexus-compiler-version>
<!-- Properties to enable jacoco code coverage analysis -->
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
@@ -275,7 +276,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
- <version>3.1.0</version>
+ <version>3.2.0</version>
</plugin>
<plugin>
@@ -336,12 +337,12 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
- <version>0.8.5</version>
+ <version>0.8.6</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
- <version>3.9.0</version>
+ <version>3.9.1</version>
<dependencies>
<dependency><!-- add support for ssh/scp -->
<groupId>org.apache.maven.wagon</groupId>
@@ -383,7 +384,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
- <version>3.1.0</version>
+ <version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
@@ -846,12 +847,12 @@
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-javac</artifactId>
- <version>2.8.6</version>
+ <version>${plexus-compiler-version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-javac-errorprone</artifactId>
- <version>2.8.6</version>
+ <version>${plexus-compiler-version}</version>
</dependency>
<!-- override plexus-compiler-javac-errorprone's dependency on
Error Prone with the latest version -->
@@ -890,12 +891,12 @@
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-eclipse</artifactId>
- <version>2.8.6</version>
+ <version>${plexus-compiler-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
- <version>3.21.0</version>
+ <version>3.23.0</version>
</dependency>
</dependencies>
</plugin>
@@ -924,12 +925,6 @@
<plugin>
<groupId>org.eclipse.tycho.extras</groupId>
<artifactId>tycho-pack200a-plugin</artifactId>
- <!-- TODO remove this configuration when https://git.eclipse.org/r/#/c/16027 is available -->
- <configuration>
- <supportedProjectTypes>
- <supportedProjectType>jar</supportedProjectType>
- </supportedProjectTypes>
- </configuration>
<executions>
<execution>
<id>pack200-normalize</id>
@@ -956,12 +951,6 @@
<plugin>
<groupId>org.eclipse.tycho.extras</groupId>
<artifactId>tycho-pack200b-plugin</artifactId>
- <!-- TODO remove this configuration when https://git.eclipse.org/r/#/c/16027 is available -->
- <configuration>
- <supportedProjectTypes>
- <supportedProjectType>jar</supportedProjectType>
- </supportedProjectTypes>
- </configuration>
<executions>
<execution>
<id>pack200-pack</id>
diff --git a/tools/maven-central/deploy.rb b/tools/maven-central/deploy.rb
index 7cab32236b..834fa94995 100755
--- a/tools/maven-central/deploy.rb
+++ b/tools/maven-central/deploy.rb
@@ -51,6 +51,7 @@ group = 'org.eclipse.jgit'
artifacts = [group,
group + '.ant',
group + '.archive',
+ group + '.gpg.bc',
group + '.http.apache',
group + '.http.server',
group + '.junit',
@@ -60,6 +61,7 @@ artifacts = [group,
group + '.lfs.server',
group + '.pgm',
group + '.ssh.apache',
+ group + '.ssh.jsch',
group + '.ui']
prefix = ["mvn", "gpg:sign-and-deploy-file", "-Dgpg.passphrase=#{passphrase}",
diff --git a/tools/maven-central/download.rb b/tools/maven-central/download.rb
index 543ae87a5d..bc48c82195 100755
--- a/tools/maven-central/download.rb
+++ b/tools/maven-central/download.rb
@@ -11,6 +11,7 @@ group = 'org.eclipse.jgit'
artifacts = [group,
group + '.ant',
group + '.archive',
+ group + '.gpg.bc',
group + '.http.apache',
group + '.http.server',
group + '.junit',
@@ -20,6 +21,7 @@ artifacts = [group,
group + '.lfs.server',
group + '.pgm',
group + '.ssh.apache',
+ group + '.ssh.jsch',
group + '.ui']
puts 'Deleting current files'
diff --git a/tools/workspace_status.py b/tools/workspace_status.py
new file mode 100644
index 0000000000..ca9e0a98c9
--- /dev/null
+++ b/tools/workspace_status.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Copyright (C) 2020, David Ostrovsky <david@ostrovsky.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
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This script will be run by bazel when the build process starts to
+# generate key-value information that represents the status of the
+# workspace. The output should be like
+#
+# KEY1 VALUE1
+# KEY2 VALUE2
+#
+# If the script exits with non-zero code, it's considered as a failure
+# and the output will be discarded.
+
+from __future__ import print_function
+import os
+import subprocess
+import sys
+
+ROOT = os.path.abspath(__file__)
+while not os.path.exists(os.path.join(ROOT, 'WORKSPACE')):
+ ROOT = os.path.dirname(ROOT)
+CMD = ['git', 'describe', '--always', '--match', 'v[0-9].*', '--dirty']
+
+
+def revision(directory, parent):
+ try:
+ os.chdir(directory)
+ return subprocess.check_output(CMD).strip().decode("utf-8")
+ except OSError as err:
+ print('could not invoke git: %s' % err, file=sys.stderr)
+ sys.exit(1)
+ except subprocess.CalledProcessError as err:
+ # ignore "not a git repository error" to report unknown version
+ return None
+ finally:
+ os.chdir(parent)
+
+
+print("STABLE_BUILD_JGIT_LABEL %s" % revision(ROOT, ROOT))

Back to the top