Merge branch 'master' into next * master: (497 commits) Prepare 7.3.0-SNAPSHOT builds Prepare 7.2.1-SNAPSHOT builds JGit v7.2.0.202503040940-r JGit v7.2.0.202503040805-r CacheRegion: fix non translatable text warnings Ensure access to autoRefresh is thread-safe FileReftableStack: use FileSnapshot to detect modification FileReftableDatabase: consider ref updates by another process BlameRegionMerger: report invalid regions with checked exception. Prepare 7.2.0-SNAPSHOT builds [ssh known_hosts] Handle unknown keys better [releng] Remove unused target platform definitions JGit v7.2.0.202502261823-rc1 [ssh known_hosts] Handle host certificates [ssh known_hosts] Improve updating modified keys [ssh known_hosts] Add tests and fix problems [ssh, releng] Remove net.i2p.crypto.eddsa AddCommand: Use parenthesis to make the operator precedence explicit AddCommand: implement --all/--no-all Do not load bitmap indexes during directory scans ... Change-Id: I619c89071f5f7a05bcd0218840f7f47bd19b779d
diff --git a/.bazelrc b/.bazelrc index efa007a..70322dd 100644 --- a/.bazelrc +++ b/.bazelrc
@@ -2,7 +2,7 @@ # https://issues.gerritcodereview.com/issues/303819949 common --noenable_bzlmod -build --workspace_status_command="python ./tools/workspace_status.py" +build --workspace_status_command="python3 ./tools/workspace_status.py" build --repository_cache=~/.gerritcodereview/bazel-cache/repository build --incompatible_strict_action_env build --action_env=PATH @@ -37,5 +37,6 @@ test --build_tests_only test --test_output=errors test --flaky_test_attempts=3 +test --test_tag_filters=-ext import %workspace%/tools/remote-bazelrc
diff --git a/.mailmap b/.mailmap index 7116ebb..1c77395 100644 --- a/.mailmap +++ b/.mailmap
@@ -1,20 +1,33 @@ +Adithya Chakilam <quic_achakila@quicinc.com> Adithya Chakilam <achakila@codeaurora.org> Chris Aniszczyk <caniszczyk@gmail.com> Chris Aniszczyk <zx@eclipsesource.com> Christian Halstrick <christian.halstrick@sap.com> Christian Halstrick <christian.halstrick@gmail.com> Dani Megert <Daniel_Megert@ch.ibm.com> Daniel Megert <daniel_megert@ch.ibm.com> +Dariusz Luksza <dariusz.luksza@gmail.com> Dariusz Luksza <dariusz@luksza.org> +David Ostrovsky <david.ostrovsky@gmail.com> David Ostrovsky <david@ostrovsky.org> David Pursehouse <david.pursehouse@gmail.com> David Pursehouse <david.pursehouse@sonymobile.com> Han-Wen Nienhuys <hanwen@google.com> Han-Wen NIenhuys <hanwen@google.com> Hector Oswaldo Caballero <hector.caballero@ericsson.com> Hector Caballero <hector.caballero@ericsson.com> +Jackson Toeniskoetter <jackdt@google.com> <jackdt@google.com> Lars Vogel <Lars.Vogel@vogella.com> Lars Vogel <Lars.Vogel@gmail.com> Mark Ingram <markdingram@gmail.com> markdingram <markdingram@gmail.com> Markus Duft <markus.duft@ssi-schaefer.com> Markus Duft <markus.duft@salomon.at> +Martin Fick <mfick@nvidia.com> Martin Fick <mfick@codeaurora.org> +Martin Fick <mfick@nvidia.com> Martin Fick <quic_mfick@quicinc.com> Michael Keppler <michael.keppler@gmx.de> Michael Keppler <Michael.Keppler@gmx.de> +Nasser Grainawi <quic_nasserg@quicinc.com> Nasser Grainawi <nasser@codeaurora.org> Roberto Tyley <roberto.tyley@guardian.co.uk> roberto <roberto.tyley@guardian.co.uk> Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com> Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com> Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <zivkov@gmail.com> Sebastian Schuberth <sschuberth@gmail.com> Sebastian Schuberth <sebastian.schuberth@bosch.io> +Sebastian Schuberth <sschuberth@gmail.com> <opensource@schuberth.dev> Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <sop@google.com> Shawn Pearce <spearce@spearce.org> Shawn Pearce <sop@google.com> Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <spearce@spearce.org> +Sven Selberg <sven.selberg@axis.com> Sven Selberg <sven.selberg@sonymobile.com> Terry Parker <tparker@google.com> tparker <tparker@google.com> Thomas Wolf <twolf@apache.org> Thomas Wolf <thomas.wolf@paranor.ch> +Tomasz Zarna <tzarna@gmail.com> <Tomasz.Zarna@pl.ibm.com> +Tomasz Zarna <tzarna@gmail.com> <tomasz.zarna@tasktop.com> +Tobias Pfeifer <to.pfeifer@web.de> <to.pfeifer@sap.com> +Yunjie Li <yunjieli@google.com> <yunjieli@google.com>
diff --git a/Documentation/config-options.md b/Documentation/config-options.md index 78930e6..4dde8f8 100644 --- a/Documentation/config-options.md +++ b/Documentation/config-options.md
@@ -31,6 +31,7 @@ | `core.dfs.blockSize` | `64 kiB` | ⃞ | Size in bytes of a single window read in from the pack file into the DFS block cache. | | `core.dfs.concurrencyLevel` | `32` | ⃞ | The estimated number of threads concurrently accessing the DFS block cache. | | `core.dfs.deltaBaseCacheLimit` | `10 MiB` | ⃞ | Maximum number of bytes to hold in per-reader DFS delta base cache. | +| `core.dfs.loadRevIndexInParallel` | false; | ⃞ | Try to load the reverse index in parallel with the bitmap index. | | `core.dfs.streamFileThreshold` | `50 MiB` | ⃞ | The size threshold beyond which objects must be streamed. | | `core.dfs.streamBuffer` | Block size of the pack | ⃞ | 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` | ⃞ | Ratio of DFS block cache to occupy with a copied pack. Values between `0` and `1.0`. | @@ -54,9 +55,13 @@ | `core.streamFileThreshold` | `50 MiB` | ⃞ | The size threshold beyond which objects must be streamed. | | `core.supportsAtomicFileCreation` | `true` | ⃞ | Whether the filesystem supports atomic file creation. | | `core.symlinks` | Auto detect if filesystem supports symlinks| ✅ | If false, symbolic links are checked out as small plain files that contain the link text. | -| `core.trustFolderStat` | `true` | ⃞ | Whether to trust the pack folder's, packed-refs file's and loose-objects folder's file attributes (Java equivalent of stat command on *nix). When looking for pack files, if `false` JGit will always scan the `.git/objects/pack` folder and if set to `true` it assumes that pack files are unchanged if the file attributes of the pack folder are unchanged. When getting the list of packed refs, if `false` JGit will always read the packed-refs file and if set to `true` it uses the file attributes of the packed-refs file and will only read it if a file attribute has changed. When looking for loose objects, if `false` and if a loose object is not found, JGit will open and close a stream to `.git/objects` folder (which can refresh its directory listing, at least on some NFS clients) and retry looking for that loose object. Setting this option to `false` can help to workaround caching issues on NFS, but reduces performance. | -| `core.trustPackedRefsStat` | `unset` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the packed-refs file. If `never` JGit will ignore the file attributes of the packed-refs file and always read it. If `always` JGit will trust the file attributes of the packed-refs file and will only read it if a file attribute has changed. `after_open` behaves the same as `always`, except that the packed-refs file is opened and closed before its file attributes are considered. An open/close of the packed-refs file is known to refresh its file attributes, at least on some NFS clients. If `unset`, JGit will use the behavior described in `trustFolderStat`. | -| `core.trustLooseRefStat` | `always` | ⃞ | Whether to trust the file attributes (Java equivalent of stat command on *nix) of the loose ref. If `always` JGit will trust the file attributes of the loose ref and its parent directories. `after_open` behaves similar to `always`, except that all parent directories of the loose ref up to the repository root are opened and closed before its file attributes are considered. An open/close of these parent directories is known to refresh the file attributes, at least on some NFS clients. | +| ~~`core.trustFolderStat`~~ | `true` | ⃞ | __Deprecated__, use `core.trustStat` instead. If set to `true` translated to `core.trustStat=always`, if `false` translated to `core.trustStat=never`, see below. If both `core.trustFolderStat` and `core.trustStat` are configured then `trustStat` takes precedence and `trustFolderStat` is ignored. | +| `core.trustLooseRefStat` | `inherit` | ⃞ | Whether to trust the file attributes of loose refs and its fan-out parent directory. See `core.trustStat` for possible values. If `inherit`, JGit will use the behavior configured in `trustStat`. | +| `core.trustPackedRefsStat` | `inherit` | ⃞ | Whether to trust the file attributes of the packed-refs file. See `core.trustStat` for possible values. If `inherit`, JGit will use the behavior configured in `core.trustStat`. | +| `core.trustTablesListStat` | `inherit` | ⃞ | Whether to trust the file attributes of the `tables.list` file used by the reftable ref storage backend to store the list of reftable filenames. See `core.trustStat` for possible values. If `inherit`, JGit will use the behavior configured in `core.trustStat`. The reftable backend is used if `extensions.refStorage = reftable`. | +| `core.trustLooseObjectStat` | `inherit` | ⃞ | Whether to trust the file attributes of the loose object file and its fan-out parent directory. See `core.trustStat` for possible values. If `inherit`, JGit will use the behavior configured in `core.trustStat`. | +| `core.trustPackStat` | `inherit` | ⃞ | Whether to trust the file attributes of the `objects/pack` directory. See `core.trustStat` for possible values. If `inherit`, JGit will use the behavior configured in `core.trustStat`. | +| `core.trustStat` | `always` | ⃞ | Global option to configure whether to trust file attributes (Java equivalent of stat command on Unix) of files storing git objects. Can be overridden for specific files by configuring `core.trustLooseRefStat, core.trustPackedRefsStat, core.trustLooseObjectStat, core.trustPackStat,core.trustTablesListStat`. If `never` JGit will ignore the file attributes of the file and always read it. If `always` JGit will trust the file attributes and will only read it if a file attribute has changed. `after_open` behaves the same as `always`, but file attributes are only considered *after* the file itself and any transient parent directories have been opened and closed. An open/close of the file/directory is known to refresh its file attributes, at least on some NFS clients. | | `core.worktree` | Root directory of the working tree if it is not the parent directory of the `.git` directory | ✅ | The path to the root of the working tree. | ## __fetch__ options @@ -130,6 +135,13 @@ | `pack.window` | `10` | ✅ | Number of objects to try when looking for a delta base per thread searching for deltas. | | `pack.windowMemory` | `0` (unlimited) | ✅ | Maximum number of bytes to put into the delta search window. | +## reftable options + +| option | default | git option | description | +|---------|---------|------------|-------------| +| `reftable.autoRefresh` | `false` | ⃞ | Whether to auto-refresh the reftable stack if it is out of date. | + + ## __repack__ options | option | default | git option | description |
diff --git a/WORKSPACE b/WORKSPACE index ab80a64..505141c 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -73,12 +73,6 @@ ) maven_jar( - name = "eddsa", - artifact = "net.i2p.crypto:eddsa:0.3.0", - sha1 = "1901c8d4d8bffb7d79027686cfb91e704217c3e1", -) - -maven_jar( name = "jsch", artifact = "com.jcraft:jsch:0.1.55", sha1 = "bbd40e5aa7aa3cfad5db34965456cee738a42a50", @@ -108,44 +102,44 @@ sha1 = "51cf043c87253c9f58b539c9f7e44c8894223850", ) -SSHD_VERS = "2.12.0" +SSHD_VERS = "2.15.0" maven_jar( name = "sshd-osgi", artifact = "org.apache.sshd:sshd-osgi:" + SSHD_VERS, - sha1 = "32b8de1cbb722ba75bdf9898e0c41d42af00ce57", + sha1 = "aa76898fe47eab7da0878dd60e6f3be5631e076c", ) maven_jar( name = "sshd-sftp", artifact = "org.apache.sshd:sshd-sftp:" + SSHD_VERS, - sha1 = "0f96f00a07b186ea62838a6a4122e8f4cad44df6", + sha1 = "2e226055ed060c64ed76256a9c45de6d0109eef8", ) -JNA_VERS = "5.14.0" +JNA_VERS = "5.16.0" maven_jar( name = "jna", artifact = "net.java.dev.jna:jna:" + JNA_VERS, - sha1 = "67bf3eaea4f0718cb376a181a629e5f88fa1c9dd", + sha1 = "ebea09f91dc9f7048099f963fb8d6f919f0a4d9c", ) maven_jar( name = "jna-platform", artifact = "net.java.dev.jna:jna-platform:" + JNA_VERS, - sha1 = "28934d48aed814f11e4c584da55c49fa7032b31b", + sha1 = "b2a9065f97c166893d504b164706512338e3bbc2", ) maven_jar( name = "commons-codec", - artifact = "commons-codec:commons-codec:1.16.0", - sha1 = "4e3eb3d79888d76b54e28b350915b5dc3919c9de", + artifact = "commons-codec:commons-codec:1.18.0", + sha1 = "ee45d1cf6ec2cc2b809ff04b4dc7aec858e0df8f", ) maven_jar( name = "commons-logging", - artifact = "commons-logging:commons-logging:1.2", - sha1 = "4bfc12adfe4842bf07b657f0369c4cb522955686", + artifact = "commons-logging:commons-logging:1.3.5", + sha1 = "a3fcc5d3c29b2b03433aa2d2f2d2c1b1638924a1", ) maven_jar( @@ -162,32 +156,38 @@ maven_jar( name = "servlet-api", - artifact = "jakarta.servlet:jakarta.servlet-api:6.0.0", - sha1 = "abecc699286e65035ebba9844c03931357a6a963", + artifact = "jakarta.servlet:jakarta.servlet-api:6.1.0", + sha1 = "1169a246913fe3823782af7943e7a103634867c5", ) maven_jar( name = "commons-compress", - artifact = "org.apache.commons:commons-compress:1.26.0", - sha1 = "659feffdd12280201c8aacb8f7be94f9a883c824", + artifact = "org.apache.commons:commons-compress:1.27.1", + sha1 = "a19151084758e2fbb6b41eddaa88e7b8ff4e6599", +) + +maven_jar( + name = "commons-lang3", + artifact = "org.apache.commons:commons-lang3:3.17.0", + sha1 = "b17d2136f0460dcc0d2016ceefca8723bdf4ee70", ) maven_jar( name = "commons-io", - artifact = "commons-io:commons-io:2.15.1", - sha1 = "f11560da189ab563a5c8e351941415430e9304ea", + artifact = "commons-io:commons-io:2.18.0", + sha1 = "44084ef756763795b31c578403dd028ff4a22950", ) maven_jar( name = "tukaani-xz", - artifact = "org.tukaani:xz:1.9", - sha1 = "1ea4bec1a921180164852c65006d928617bd2caf", + artifact = "org.tukaani:xz:1.10", + sha1 = "1be8166f89e035a56c6bfc67dbc423996fe577e2", ) maven_jar( name = "args4j", - artifact = "args4j:args4j:2.33", - sha1 = "bd87a75374a6d6523de82fef51fc3cfe9baf9fc9", + artifact = "args4j:args4j:2.37", + sha1 = "244f60c057d72a785227c0562d3560f42a7ea54b", ) maven_jar( @@ -204,126 +204,114 @@ maven_jar( name = "mockito", - artifact = "org.mockito:mockito-core:5.10.0", - sha1 = "b3812fa2ee069f1d0b41c1c0155da79d0e1dcde0", + artifact = "org.mockito:mockito-core:5.15.2", + sha1 = "87be4b1e0cc5febc07ab3197a8ff3ede56b37a79", ) maven_jar( name = "assertj-core", - artifact = "org.assertj:assertj-core:3.25.3", - sha1 = "792b270e73aa1cfc28fa135be0b95e69ea451432", + artifact = "org.assertj:assertj-core:3.27.3", + sha1 = "31f5d58a202bd5df4993fb10fa2cffd610c20d6f", ) -BYTE_BUDDY_VERSION = "1.14.12" +BYTE_BUDDY_VERSION = "1.17.1" maven_jar( name = "bytebuddy", artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, - sha1 = "6e37f743dc15a8d7a4feb3eb0025cbc612d5b9e1", + sha1 = "8b5205fad48196a88d3d66dddff5a7417bce3596", ) maven_jar( name = "bytebuddy-agent", artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, - sha1 = "be4984cb6fd1ef1d11f218a648889dfda44b8a15", + sha1 = "0669a13b59d5ffd8198a79e4dc99018a9278e457", ) maven_jar( name = "objenesis", - artifact = "org.objenesis:objenesis:3.3", - sha1 = "1049c09f1de4331e8193e579448d0916d75b7631", + artifact = "org.objenesis:objenesis:3.4", + sha1 = "675cbe121a68019235d27f6c34b4f0ac30e07418", ) maven_jar( name = "gson", - artifact = "com.google.code.gson:gson:2.10.1", - sha1 = "b3add478d4382b78ea20b1671390a858002feb6c", + artifact = "com.google.code.gson:gson:2.12.1", + sha1 = "4e773a317740b83b43cfc3d652962856041697cb", ) -JETTY_VER = "12.0.9" +JETTY_VER = "12.0.16" maven_jar( name = "jetty-servlet", artifact = "org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VER, - sha1 = "19e056d75741e7348411d677a9b26a54ea4b7d16", - src_sha1 = "d7fcb4e9d259c1dd8595c6163054be449072fe14", + sha1 = "022a746c00b1ac5c790fee65a398c707160a46d8", ) maven_jar( name = "jetty-security", artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER, - sha1 = "0c03a77f9d1a8b595cb4a83011cef735bd34bc95", - src_sha1 = "9fba93bbce1466ef9c77d7a75338abd479641721", + sha1 = "23b1a3abecf9d6f5498064a32d9145ae1d8330f9", ) maven_jar( name = "jetty-server", artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER, - sha1 = "87adc518dd68b674e08d7e4968d07b6dc73214f1", - src_sha1 = "5404f097aae0126b820b040b4e924f31fe4ff25b", + sha1 = "3e3638b4bfbee04c27b3ae68e4949fc43b40a042", ) maven_jar( name = "jetty-session", artifact = "org.eclipse.jetty:jetty-session:" + JETTY_VER, - sha1 = "628444f02dfbc4efbd1920a12e055580b227e86b", - src_sha1 = "2ac0ca2c84fa8e40655af1482a9c67d60d659ad2", + sha1 = "79cdedc7afebbdba4453f603dfe2f970baa35cc3", ) maven_jar( name = "jetty-http", artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER, - sha1 = "cb54f006b1484306bc4b24dc3802cff472a6ba82", - src_sha1 = "a1a6bc169e06007cabf6534fd7c7d1f2e91ab775", + sha1 = "68019fa90e8420ae15c109bd8c8611cacbaf43e5", ) maven_jar( name = "jetty-io", artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER, - sha1 = "03e8f5b5c6d583ea591064671c23b8639c132052", - src_sha1 = "41b5752f3aa4c77f872649c215142aee1d6a3395", + sha1 = "7a162c537a99bbaf35a074fec9a50815e6c81d9d", ) maven_jar( name = "jetty-util", artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER, - sha1 = "996ebc69825af41d49e2edc6796eb714acdc3369", - src_sha1 = "fe3b4ecf5a176bfd3c0055e5e1490503d90965e8", + sha1 = "e262e505363e5925df15618622d9888aefc1b0d0", ) maven_jar( name = "jetty-util-ajax", artifact = "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VER, - sha1 = "634f67e811e0ad2acb32feaaf409927d80cd69ae", - src_sha1 = "192f1e1254f659af64c6cd1124807fa12bdfa721", + sha1 = "60225034131e3f771b40bc75c15bd9cc4952302b", ) -BOUNCYCASTLE_VER = "1.77" +BOUNCYCASTLE_VER = "1.80" maven_jar( name = "bcpg", artifact = "org.bouncycastle:bcpg-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "bb0be51e8b378baae6e0d86f5282cd3887066539", - src_sha1 = "33ff3269cede7165dac44033a3b150cc9f9f11cf", + sha1 = "163889a825393854dbe7dc52f1a8667e715e9859", ) maven_jar( name = "bcprov", artifact = "org.bouncycastle:bcprov-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "2cc971b6c20949c1ff98d1a4bc741ee848a09523", - src_sha1 = "14ea9a3d759261358c6a1f59490ded125b5273a6", + sha1 = "e22100b41042decf09cab914a5af8d2c57b5ac4a", ) maven_jar( name = "bcutil", artifact = "org.bouncycastle:bcutil-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "de3eaef351545fe8562cf29ddff4a403a45b49b7", - src_sha1 = "6f8f56ab009e7a3204817a0d45ed9638f5e30116", + sha1 = "b95726d1d49a0c65010c59a3e6640311d951bfd1", ) maven_jar( name = "bcpkix", artifact = "org.bouncycastle:bcpkix-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "ed953791ba0229747dd0fd9911e3d76a462acfd3", - src_sha1 = "fdff397d5de0306db014f0a17e91717150db2768", + sha1 = "5277dfaaef2e92ce1d802499599a0ca7488f86e6", )
diff --git a/lib/BUILD b/lib/BUILD index c2a8271..d236b3a 100644 --- a/lib/BUILD +++ b/lib/BUILD
@@ -20,6 +20,16 @@ ) java_library( + name = "commons-lang3", + visibility = [ + "//org.eclipse.jgit.archive:__pkg__", + "//org.eclipse.jgit.pgm.test:__pkg__", + "//org.eclipse.jgit.test:__pkg__", + ], + exports = ["@commons-lang3//jar"], +) + +java_library( name = "commons-io", visibility = [ "//org.eclipse.jgit.archive:__pkg__", @@ -45,16 +55,6 @@ ) java_library( - name = "eddsa", - visibility = [ - "//org.eclipse.jgit.ssh.apache:__pkg__", - "//org.eclipse.jgit.ssh.apache.test:__pkg__", - "//org.eclipse.jgit.ssh.jsch.test:__pkg__", - ], - exports = ["@eddsa//jar"], -) - -java_library( name = "gson", visibility = [ "//org.eclipse.jgit.lfs:__pkg__", @@ -208,6 +208,8 @@ visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", "//org.eclipse.jgit.gpg.bc.test:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", + "//org.eclipse.jgit.ssh.jsch.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], exports = ["@bcprov//jar"], @@ -218,6 +220,8 @@ visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", "//org.eclipse.jgit.gpg.bc.test:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", + "//org.eclipse.jgit.ssh.jsch.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], exports = ["@bcutil//jar"], @@ -227,6 +231,8 @@ name = "bcpkix", visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", + "//org.eclipse.jgit.ssh.jsch.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], exports = ["@bcpkix//jar"],
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index 7c079a5..fa9a416 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -5,13 +5,13 @@ Automatic-Module-Name: org.eclipse.jgit.ant.test Bundle-SymbolicName: org.eclipse.jgit.ant.test Bundle-Vendor: %Bundle-Vendor -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.ant.tasks;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", + org.eclipse.jgit.ant.tasks;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.hamcrest.core;version="[1.1.0,3.0.0)", org.junit;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml index be954bd..4a54d87 100644 --- a/org.eclipse.jgit.ant.test/pom.xml +++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF index b6b52e5..480d88e 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -3,13 +3,13 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ant Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)" + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)" Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.ant;version="7.0.0", - org.eclipse.jgit.ant.tasks;version="7.0.0"; +Export-Package: org.eclipse.jgit.ant;version="7.3.0", + org.eclipse.jgit.ant.tasks;version="7.3.0"; uses:="org.apache.tools.ant, org.apache.tools.ant.types"
diff --git a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF index 22f8aff..136b7cf 100644 --- a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.ant - Sources Bundle-SymbolicName: org.eclipse.jgit.ant.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ant;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ant;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index 7c3edf4..4e85ee4 100644 --- a/org.eclipse.jgit.ant/pom.xml +++ b/org.eclipse.jgit.ant/pom.xml
@@ -15,7 +15,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ant</artifactId>
diff --git a/org.eclipse.jgit.archive/BUILD b/org.eclipse.jgit.archive/BUILD index 3d7dbd2..d4f5340 100644 --- a/org.eclipse.jgit.archive/BUILD +++ b/org.eclipse.jgit.archive/BUILD
@@ -12,6 +12,7 @@ resources = glob(["resources/**"]), deps = [ "//lib:commons-compress", + "//lib:commons-lang3", # We want these deps to be provided_deps "//org.eclipse.jgit:jgit", ],
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF index e1a3671..fdfc635 100644 --- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.archive Bundle-SymbolicName: org.eclipse.jgit.archive -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -13,17 +13,18 @@ org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)", org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)", org.apache.commons.compress.compressors.xz;version="[1.4,2.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.osgi.framework;version="[1.3.0,2.0.0)" + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.osgi.framework;version="[1.3.0,2.0.0)", + org.tukaani.xz Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.jgit.archive.FormatActivator -Export-Package: org.eclipse.jgit.archive;version="7.0.0"; - uses:="org.eclipse.jgit.lib, +Export-Package: org.eclipse.jgit.archive;version="7.3.0"; + uses:="org.apache.commons.compress.archivers, + org.osgi.framework, org.eclipse.jgit.api, - org.apache.commons.compress.archivers, - org.osgi.framework", - org.eclipse.jgit.archive.internal;version="7.0.0";x-internal:=true + org.eclipse.jgit.lib", + org.eclipse.jgit.archive.internal;version="7.3.0";x-internal:=true
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF index 322f52f..716e8d0 100644 --- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.archive - Sources Bundle-SymbolicName: org.eclipse.jgit.archive.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.archive;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.archive;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml index 054aa59..3935dfa 100644 --- a/org.eclipse.jgit.archive/pom.xml +++ b/org.eclipse.jgit.archive/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.archive</artifactId> @@ -41,6 +41,11 @@ </dependency> <dependency> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + </dependency> + + <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> <version>${project.version}</version>
diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml index d8a616f..87d2bb3 100644 --- a/org.eclipse.jgit.benchmarks/pom.xml +++ b/org.eclipse.jgit.benchmarks/pom.xml
@@ -16,7 +16,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.benchmarks</artifactId> @@ -52,6 +52,10 @@ <artifactId>org.eclipse.jgit.junit</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> </dependencies> <build> @@ -79,7 +83,6 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <version>${maven-compiler-plugin-version}</version> <configuration> <encoding>UTF-8</encoding> <release>${java.version}</release>
diff --git a/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java index 52a881b..44e862e 100644 --- a/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java +++ b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/GetRefsBenchmark.java
@@ -24,10 +24,12 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.internal.storage.file.FileReftableDatabase; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.CoreConfig.TrustStat; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; @@ -38,8 +40,10 @@ import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; +import org.junit.Assume; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; @@ -66,11 +70,14 @@ public static class BenchmarkState { @Param({ "true", "false" }) boolean useRefTable; - @Param({ "100", "2500", "10000", "50000" }) + @Param({ "true", "false" }) + boolean autoRefresh; + + @Param({ "100", "1000", "10000", "100000" }) int numBranches; - @Param({ "true", "false" }) - boolean trustFolderStat; + @Param({ "ALWAYS", "AFTER_OPEN", "NEVER" }) + TrustStat trustStat; List<String> branches = new ArrayList<>(numBranches); @@ -81,10 +88,13 @@ public static class BenchmarkState { @Setup @SuppressWarnings("boxing") public void setupBenchmark() throws IOException, GitAPIException { + // if we use RefDirectory skip autoRefresh = false + Assume.assumeTrue(useRefTable || autoRefresh); + String firstBranch = "firstbranch"; testDir = Files.createDirectory(Paths.get("testrepos")); - String repoName = "branches-" + numBranches + "-trustFolderStat-" - + trustFolderStat + "-" + refDatabaseType(); + String repoName = "branches-" + numBranches + "-trustStat-" + + trustStat + "-" + refDatabaseType(); Path workDir = testDir.resolve(repoName); Path repoPath = workDir.resolve(".git"); Git git = Git.init().setDirectory(workDir.toFile()).call(); @@ -97,10 +107,13 @@ public void setupBenchmark() throws IOException, GitAPIException { ((FileRepository) git.getRepository()).convertRefStorage( ConfigConstants.CONFIG_REF_STORAGE_REFTABLE, false, false); + FileReftableDatabase refdb = (FileReftableDatabase) git + .getRepository().getRefDatabase(); + refdb.setAutoRefresh(autoRefresh); } else { - cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, - trustFolderStat); + cfg.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_TRUST_STAT, + trustStat); } cfg.setInt(ConfigConstants.CONFIG_RECEIVE_SECTION, null, "maxCommandBytes", Integer.MAX_VALUE); @@ -112,7 +125,8 @@ public void setupBenchmark() throws IOException, GitAPIException { System.out.println("Preparing test"); System.out.println("- repository: \t\t" + repoPath); System.out.println("- refDatabase: \t\t" + refDatabaseType()); - System.out.println("- trustFolderStat: \t" + trustFolderStat); + System.out.println("- autoRefresh: \t\t" + autoRefresh); + System.out.println("- trustStat: \t" + trustStat); System.out.println("- branches: \t\t" + numBranches); BatchRefUpdate u = repo.getRefDatabase().newBatchUpdate(); @@ -152,7 +166,8 @@ public void teardown() throws IOException { @BenchmarkMode({ Mode.AverageTime }) @OutputTimeUnit(TimeUnit.MICROSECONDS) @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS) - @Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(2) public void testGetExactRef(Blackhole blackhole, BenchmarkState state) throws IOException { String branchName = state.branches @@ -164,7 +179,8 @@ public void testGetExactRef(Blackhole blackhole, BenchmarkState state) @BenchmarkMode({ Mode.AverageTime }) @OutputTimeUnit(TimeUnit.MICROSECONDS) @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS) - @Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(2) public void testGetRefsByPrefix(Blackhole blackhole, BenchmarkState state) throws IOException { String branchPrefix = "refs/heads/branch/" + branchIndex.nextInt(100)
diff --git a/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/RawTextBenchmark.java b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/RawTextBenchmark.java new file mode 100644 index 0000000..19297eb --- /dev/null +++ b/org.eclipse.jgit.benchmarks/src/org/eclipse/jgit/benchmarks/RawTextBenchmark.java
@@ -0,0 +1,454 @@ +/* + * Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.benchmarks; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.concurrent.TimeUnit; + +import static org.eclipse.jgit.diff.RawText.getBufferSize; +import static org.eclipse.jgit.diff.RawText.isBinary; +import static org.eclipse.jgit.diff.RawText.isCrLfText; + +@State(Scope.Thread) +public class RawTextBenchmark { + + @State(Scope.Benchmark) + public static class BenchmarkState { + + @Param({"1", "2", "3", "4", "5", "6"}) + int testIndex; + + @Param({"false", "true"}) + boolean complete; + + byte[] bytes; + + @Setup + public void setupBenchmark() { + switch (testIndex) { + case 1: { + byte[] tmpBytes = "a".repeat(102400).getBytes(); + bytes = tmpBytes; + break; + } + case 2: { + byte[] tmpBytes = "a".repeat(102400).getBytes(); + byte[] tmpBytes2 = new byte[tmpBytes.length + 1]; + System.arraycopy(tmpBytes, 0, tmpBytes2, 0, tmpBytes.length); + tmpBytes2[500] = '\0'; + tmpBytes2[tmpBytes.length] = '\0'; + bytes = tmpBytes2; + break; + } + case 3: { + byte[] tmpBytes = "a".repeat(102400).getBytes(); + byte[] tmpBytes2 = new byte[tmpBytes.length + 1]; + System.arraycopy(tmpBytes, 0, tmpBytes2, 0, tmpBytes.length); + tmpBytes2[500] = '\r'; + tmpBytes2[tmpBytes.length] = '\r'; + bytes = tmpBytes2; + break; + } + case 4: { + byte[] tmpBytes = "a".repeat(102400).getBytes(); + byte[] tmpBytes2 = new byte[tmpBytes.length + 1]; + System.arraycopy(tmpBytes, 0, tmpBytes2, 0, tmpBytes.length); + tmpBytes2[499] = '\r'; + tmpBytes2[500] = '\n'; + tmpBytes2[tmpBytes.length - 1] = '\r'; + tmpBytes2[tmpBytes.length] = '\n'; + bytes = tmpBytes2; + break; + } + case 5: { + byte[] tmpBytes = "a".repeat(102400).getBytes(); + tmpBytes[0] = '\0'; + bytes = tmpBytes; + break; + } + case 6: { + byte[] tmpBytes = "a".repeat(102400).getBytes(); + tmpBytes[0] = '\r'; + bytes = tmpBytes; + break; + } + default: + } + } + + @TearDown + public void teardown() { + } + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsCrLfTextOld(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isCrLfTextOld( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsCrLfTextNewCandidate1(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isCrLfTextNewCandidate1( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsCrLfTextNewCandidate2(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isCrLfTextNewCandidate2( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsCrLfTextNewCandidate3(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isCrLfTextNewCandidate3( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsCrLfTextNew(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isCrLfText( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsBinaryOld(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isBinaryOld( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(1) + public void testIsBinaryNew(Blackhole blackhole, BenchmarkState state) { + blackhole.consume( + isBinary( + state.bytes, + state.bytes.length, + state.complete + ) + ); + } + + + /** + * Determine heuristically whether a byte array represents binary (as + * opposed to text) content. + * + * @param raw + * the raw file content. + * @param length + * number of bytes in {@code raw} to evaluate. This should be + * {@code raw.length} unless {@code raw} was over-allocated by + * the caller. + * @param complete + * whether {@code raw} contains the whole data + * @return true if raw is likely to be a binary file, false otherwise + * @since 6.0 + */ + public static boolean isBinaryOld(byte[] raw, int length, boolean complete) { + // Similar heuristic as C Git. Differences: + // - limited buffer size; may be only the beginning of a large blob + // - no counting of printable vs. non-printable bytes < 0x20 and 0x7F + int maxLength = getBufferSize(); + boolean isComplete = complete; + if (length > maxLength) { + // We restrict the length in all cases to getBufferSize() to get + // predictable behavior. Sometimes we load streams, and sometimes we + // have the full data in memory. With streams, we never look at more + // than the first getBufferSize() bytes. If we looked at more when + // we have the full data, different code paths in JGit might come to + // different conclusions. + length = maxLength; + isComplete = false; + } + byte last = 'x'; // Just something inconspicuous. + for (int ptr = 0; ptr < length; ptr++) { + byte curr = raw[ptr]; + if (isBinary(curr, last)) { + return true; + } + last = curr; + } + if (isComplete) { + // Buffer contains everything... + return last == '\r'; // ... so this must be a lone CR + } + return false; + } + + /** + * Determine heuristically whether a byte array represents text content + * using CR-LF as line separator. + * + * @param raw the raw file content. + * @param length number of bytes in {@code raw} to evaluate. + * @param complete whether {@code raw} contains the whole data + * @return {@code true} if raw is likely to be CR-LF delimited text, + * {@code false} otherwise + * @since 6.0 + */ + public static boolean isCrLfTextOld(byte[] raw, int length, boolean complete) { + boolean has_crlf = false; + byte last = 'x'; // Just something inconspicuous + for (int ptr = 0; ptr < length; ptr++) { + byte curr = raw[ptr]; + if (isBinary(curr, last)) { + return false; + } + if (curr == '\n' && last == '\r') { + has_crlf = true; + } + last = curr; + } + if (last == '\r') { + if (complete) { + // Lone CR: it's binary after all. + return false; + } + // Tough call. If the next byte, which we don't have, would be a + // '\n', it'd be a CR-LF text, otherwise it'd be binary. Just decide + // based on what we already scanned; it wasn't binary until now. + } + return has_crlf; + } + + /** + * Determine heuristically whether a byte array represents text content + * using CR-LF as line separator. + * + * @param raw + * the raw file content. + * @param length + * number of bytes in {@code raw} to evaluate. + * @return {@code true} if raw is likely to be CR-LF delimited text, + * {@code false} otherwise + * @param complete + * whether {@code raw} contains the whole data + * @since 6.0 + */ + public static boolean isCrLfTextNewCandidate1(byte[] raw, int length, boolean complete) { + boolean has_crlf = false; + + // first detect empty + if (length <= 0) { + return false; + } + + // next detect '\0' + for (int reversePtr = length - 1; reversePtr >= 0; --reversePtr) { + if (raw[reversePtr] == '\0') { + return false; + } + } + + // if '\r' be last, then if complete then return non-crlf + if (raw[length - 1] == '\r' && complete) { + return false; + } + + for (int ptr = 0; ptr < length - 1; ptr++) { + byte curr = raw[ptr]; + if (curr == '\r') { + byte next = raw[ptr + 1]; + if (next != '\n') { + return false; + } + // else + // we have crlf here + has_crlf = true; + // as next is '\n', it can never be '\r', just skip it from next check + ++ptr; + } + } + + return has_crlf; + } + + /** + * Determine heuristically whether a byte array represents text content + * using CR-LF as line separator. + * + * @param raw + * the raw file content. + * @param length + * number of bytes in {@code raw} to evaluate. + * @return {@code true} if raw is likely to be CR-LF delimited text, + * {@code false} otherwise + * @param complete + * whether {@code raw} contains the whole data + * @since 6.0 + */ + public static boolean isCrLfTextNewCandidate2(byte[] raw, int length, boolean complete) { + boolean has_crlf = false; + + // first detect empty + if (length <= 0) { + return false; + } + + // if '\r' be last, then if complete then return non-crlf + byte last = raw[length - 1]; + if (last == '\0' || last == '\r' && complete) { + return false; + } + + for (int ptr = 0; ptr < length - 1; ptr++) { + byte b = raw[ptr]; + switch (b) { + case '\0': + return false; + case '\r': { + ++ptr; + b = raw[ptr]; + if (b != '\n') { + return false; + } + // else + // we have crlf here + has_crlf = true; + // as next is '\n', it can never be '\r', just skip it from next check + break; + } + default: + // do nothing; + break; + } + } + + return has_crlf; + } + + /** + * Determine heuristically whether a byte array represents text content + * using CR-LF as line separator. + * + * @param raw + * the raw file content. + * @param length + * number of bytes in {@code raw} to evaluate. + * @return {@code true} if raw is likely to be CR-LF delimited text, + * {@code false} otherwise + * @param complete + * whether {@code raw} contains the whole data + * @since 6.0 + */ + public static boolean isCrLfTextNewCandidate3(byte[] raw, int length, boolean complete) { + boolean has_crlf = false; + + int ptr = -1; + byte current; + while (ptr < length - 2) { + current = raw[++ptr]; + if ('\0' == current || '\r' == current && (raw[++ptr] != '\n' || !(has_crlf = true))) { + return false; + } + } + + if (ptr == length - 2) { + // if '\r' be last, then if isComplete then return binary + current = raw[++ptr]; + if('\0' == current || '\r' == current && complete){ + return false; + } + } + + return has_crlf; + } + + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(RawTextBenchmark.class.getSimpleName()) + .forks(1).jvmArgs("-ea").build(); + new Runner(opt).run(); + } +}
diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml index 1fe5318..8cab250 100644 --- a/org.eclipse.jgit.coverage/pom.xml +++ b/org.eclipse.jgit.coverage/pom.xml
@@ -14,7 +14,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -27,88 +27,88 @@ <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ant</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.archive</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.apache</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.server</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.server</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ui</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ssh.apache</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ant.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.server.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF index 27510e2..287d75f 100644 --- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -3,19 +3,20 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.gpg.bc.test Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" -Import-Package: org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)", - org.bouncycastle.openpgp;version="[1.65.0,2.0.0)", - org.bouncycastle.openpgp.operator;version="[1.65.0,2.0.0)", - org.bouncycastle.openpgp.operator.jcajce;version="[1.65.0,2.0.0)", - org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)", - org.eclipse.jgit.gpg.bc.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.gpg.bc.internal.keys;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.sha1;version="[7.0.0,7.1.0)", +Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.79.0,2.0.0)", + org.bouncycastle.jce.provider;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.79.0,2.0.0)", + org.eclipse.jgit.gpg.bc.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.gpg.bc.internal.keys;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.sha1;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)", org.junit.runners;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.gpg.bc.test/pom.xml b/org.eclipse.jgit.gpg.bc.test/pom.xml index d865b13..10aa742 100644 --- a/org.eclipse.jgit.gpg.bc.test/pom.xml +++ b/org.eclipse.jgit.gpg.bc.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.gpg.bc.test</artifactId>
diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java index fed0610..d486c97 100644 --- a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java +++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.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 @@ -9,10 +9,7 @@ */ package org.eclipse.jgit.gpg.bc.internal.keys; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import java.io.BufferedInputStream; import java.io.IOException; @@ -20,8 +17,6 @@ import java.security.Security; import java.util.Iterator; -import javax.crypto.Cipher; - import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; @@ -49,39 +44,15 @@ public static void ensureBC() { } } - private static volatile Boolean haveOCB; - - private static boolean ocbAvailable() { - Boolean haveIt = haveOCB; - if (haveIt != null) { - return haveIt.booleanValue(); - } - try { - Cipher c = Cipher.getInstance("AES/OCB/NoPadding"); //$NON-NLS-1$ - if (c == null) { - haveOCB = Boolean.FALSE; - return false; - } - } catch (NoClassDefFoundError | Exception e) { - haveOCB = Boolean.FALSE; - return false; - } - haveOCB = Boolean.TRUE; - return true; - } - private static class TestData { final String name; final boolean encrypted; - final boolean keyValue; - - TestData(String name, boolean encrypted, boolean keyValue) { + TestData(String name, boolean encrypted) { this.name = name; this.encrypted = encrypted; - this.keyValue = keyValue; } @Override @@ -93,19 +64,12 @@ public String toString() { @Parameters(name = "{0}") public static TestData[] initTestData() { return new TestData[] { - new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false, false), - new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false, true), - new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true, true), - new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true, true), - new TestData("62D43D7F117F7A5E4998ECB6617EE9942D069C14", true, true), - new TestData("faked", false, true) }; - } - - private static byte[] readTestKey(String filename) throws Exception { - try (InputStream in = new BufferedInputStream( - SecretKeysTest.class.getResourceAsStream(filename))) { - return SecretKeys.keyFromNameValueFormat(in); - } + new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false), + new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false), + new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true), + new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true), + new TestData("62D43D7F117F7A5E4998ECB6617EE9942D069C14", true), + new TestData("faked", false) }; } private static PGPPublicKey readAsc(InputStream in) @@ -131,11 +95,6 @@ private static PGPPublicKey readAsc(InputStream in) @Test public void testKeyRead() throws Exception { - if (data.keyValue) { - byte[] bytes = readTestKey(data.name + ".key"); - assertEquals('(', bytes[0]); - assertEquals(')', bytes[bytes.length - 1]); - } try (InputStream pubIn = this.getClass() .getResourceAsStream(data.name + ".asc")) { if (pubIn != null) { @@ -151,11 +110,6 @@ public void testKeyRead() throws Exception { : null, publicKey); assertNotNull(secretKey); - } catch (PGPException e) { - // Currently we may not be able to load OCB-encrypted keys. - assertTrue(e.toString(), e.getMessage().contains("OCB")); - assertTrue(data.encrypted); - assertFalse(ocbAvailable()); } } }
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF index 9749ac1..f35e5e5 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -3,34 +3,28 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.gpg.bc Bundle-SymbolicName: org.eclipse.jgit.gpg.bc;singleton:=true -Fragment-Host: org.eclipse.jgit;bundle-version="[7.0.0,7.1.0)" +Fragment-Host: org.eclipse.jgit;bundle-version="[7.3.0,7.4.0)" Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/gpg_bc -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.bouncycastle.asn1;version="[1.69.0,2.0.0)", - org.bouncycastle.asn1.x9;version="[1.69.0,2.0.0)", - org.bouncycastle.bcpg;version="[1.69.0,2.0.0)", - org.bouncycastle.bcpg.sig;version="[1.69.0,2.0.0)", - org.bouncycastle.crypto.ec;version="[1.69.0,2.0.0)", - org.bouncycastle.gpg;version="[1.69.0,2.0.0)", - org.bouncycastle.gpg.keybox;version="[1.69.0,2.0.0)", - org.bouncycastle.gpg.keybox.jcajce;version="[1.69.0,2.0.0)", - org.bouncycastle.jcajce.interfaces;version="[1.69.0,2.0.0)", - org.bouncycastle.jcajce.util;version="[1.69.0,2.0.0)", - org.bouncycastle.jce.provider;version="[1.69.0,2.0.0)", - org.bouncycastle.math.ec;version="[1.69.0,2.0.0)", - org.bouncycastle.math.field;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp.jcajce;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp.operator;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp.operator.jcajce;version="[1.69.0,2.0.0)", - org.bouncycastle.util;version="[1.69.0,2.0.0)", - org.bouncycastle.util.encoders;version="[1.69.0,2.0.0)", - org.bouncycastle.util.io;version="[1.69.0,2.0.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", +Import-Package: org.bouncycastle.asn1;version="[1.79.0,2.0.0)", + org.bouncycastle.asn1.x9;version="[1.79.0,2.0.0)", + org.bouncycastle.bcpg;version="[1.79.0,2.0.0)", + org.bouncycastle.bcpg.sig;version="[1.79.0,2.0.0)", + org.bouncycastle.crypto.ec;version="[1.79.0,2.0.0)", + org.bouncycastle.gpg;version="[1.79.0,2.0.0)", + org.bouncycastle.gpg.keybox;version="[1.79.0,2.0.0)", + org.bouncycastle.gpg.keybox.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.jcajce.interfaces;version="[1.79.0,2.0.0)", + org.bouncycastle.jcajce.util;version="[1.79.0,2.0.0)", + org.bouncycastle.math.ec;version="[1.79.0,2.0.0)", + org.bouncycastle.math.field;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.79.0,2.0.0)", org.slf4j;version="[1.7.0,3.0.0)" -Export-Package: org.eclipse.jgit.gpg.bc;version="7.0.0", - org.eclipse.jgit.gpg.bc.internal;version="7.0.0";x-friends:="org.eclipse.jgit.gpg.bc.test", - org.eclipse.jgit.gpg.bc.internal.keys;version="7.0.0";x-friends:="org.eclipse.jgit.gpg.bc.test" +Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.3.0";x-friends:="org.eclipse.jgit.gpg.bc.test", + org.eclipse.jgit.gpg.bc.internal.keys;version="7.3.0";x-friends:="org.eclipse.jgit.gpg.bc.test"
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF index 0733a68..5134716 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.gpg.bc - Sources Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.gpg.bc/about.html b/org.eclipse.jgit.gpg.bc/about.html index fc527d5..92b9409 100644 --- a/org.eclipse.jgit.gpg.bc/about.html +++ b/org.eclipse.jgit.gpg.bc/about.html
@@ -58,32 +58,6 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p> -<hr> -<p><b>org.eclipse.jgit.gpg.bc.internal.keys.SExprParser - MIT</b></p> - -<p>Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. -(<a href="https://www.bouncycastle.org">https://www.bouncycastle.org</a>)</p> - -<p> -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -</p> -<p> -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. -</p> -<p> -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -</p> - </body> </html>
diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml index f4dce68..6159129 100644 --- a/org.eclipse.jgit.gpg.bc/pom.xml +++ b/org.eclipse.jgit.gpg.bc/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.gpg.bc</artifactId> @@ -160,7 +160,7 @@ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications> <onlyBinaryIncompatible>false</onlyBinaryIncompatible> <includeSynthetic>false</includeSynthetic> - <ignoreMissingClasses>false</ignoreMissingClasses> + <ignoreMissingClasses>true</ignoreMissingClasses> <skipPomModules>true</skipPomModules> </parameter> <skip>false</skip>
diff --git a/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSigner b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSigner deleted file mode 100644 index 6752b64..0000000 --- a/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSigner +++ /dev/null
@@ -1 +0,0 @@ -org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSigner
diff --git a/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.SignatureVerifierFactory similarity index 100% rename from org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.GpgSignatureVerifierFactory rename to org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.SignatureVerifierFactory
diff --git a/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.SignerFactory b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.SignerFactory new file mode 100644 index 0000000..c0b214d --- /dev/null +++ b/org.eclipse.jgit.gpg.bc/resources/META-INF/services/org.eclipse.jgit.lib.SignerFactory
@@ -0,0 +1 @@ +org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSignerFactory
diff --git a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties index 77ca2cd..9e7f98c 100644 --- a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties +++ b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties
@@ -1,7 +1,5 @@ corrupt25519Key=Ed25519/Curve25519 public key has wrong length: {0} credentialPassphrase=Passphrase -cryptCipherError=Cannot create cipher to decrypt: {0} -cryptWrongDecryptedLength=Decrypted key has wrong length; expected {0} bytes, got only {1} bytes gpgFailedToParseSecretKey=Failed to parse secret key file {0}. Is the entered passphrase correct? gpgNoCredentialsProvider=missing credentials provider gpgNoKeygrip=Cannot find key {0}: cannot determine key grip @@ -9,22 +7,14 @@ gpgNoKeyInLegacySecring=no matching secret key found in legacy secring.gpg for key or user id: {0} gpgNoPublicKeyFound=Unable to find a public-key with key or user id: {0} gpgNoSecretKeyForPublicKey=unable to find associated secret key for public key: {0} -gpgNoSuchAlgorithm=Cannot decrypt encrypted secret key: encryption algorithm {0} is not available gpgNotASigningKey=Secret key ({0}) is not suitable for signing gpgKeyInfo=GPG Key (fingerprint {0}) gpgSigningCancelled=Signing was cancelled +keyAlgorithmMismatch=Secret key has a different algorithm than the public key +keyMismatch=Secret key does not match public key; public key is {0} {1} while secret key is for {2} {3} logWarnGnuPGHome=Cannot access GPG home directory given by environment variable GNUPGHOME={} logWarnGpgHomeProperty=Cannot access GPG home directory given by Java system property jgit.gpg.home={} nonSignatureError=Signature does not decode into a signature object -secretKeyTooShort=Secret key file corrupt; only {0} bytes read -sexprHexNotClosed=Hex number in s-expression not closed -sexprHexOdd=Hex number in s-expression has an odd number of digits -sexprStringInvalidEscape=Invalid escape {0} in s-expression -sexprStringInvalidEscapeAtEnd=Invalid s-expression: quoted string ends with escape character -sexprStringInvalidHexEscape=Invalid hex escape in s-expression -sexprStringInvalidOctalEscape=Invalid octal escape in s-expression -sexprStringNotClosed=String in s-expression not closed -sexprUnhandled=Unhandled token {0} in s-expression signatureInconsistent=Inconsistent signature; key ID {0} does not match issuer fingerprint {1} signatureKeyLookupError=Error occurred while looking for public key signatureNoKeyInfo=No way to determine a public key from the signature
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java deleted file mode 100644 index fdd1a2b..0000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/BouncyCastleGpgSignerFactory.java +++ /dev/null
@@ -1,34 +0,0 @@ -/* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.gpg.bc; - -import org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSigner; -import org.eclipse.jgit.lib.GpgSigner; - -/** - * Factory for creating a {@link GpgSigner} based on Bouncy Castle. - * - * @since 5.11 - */ -public final class BouncyCastleGpgSignerFactory { - - private BouncyCastleGpgSignerFactory() { - // No instantiation - } - - /** - * Creates a new {@link GpgSigner}. - * - * @return the {@link GpgSigner} - */ - public static GpgSigner create() { - return new BouncyCastleGpgSigner(); - } -}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java index 705e195..fcae7c2 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2021 Salesforce and others + * Copyright (C) 2018, 2024 Salesforce and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -30,8 +30,6 @@ public static BCText get() { // @formatter:off /***/ public String corrupt25519Key; /***/ public String credentialPassphrase; - /***/ public String cryptCipherError; - /***/ public String cryptWrongDecryptedLength; /***/ public String gpgFailedToParseSecretKey; /***/ public String gpgNoCredentialsProvider; /***/ public String gpgNoKeygrip; @@ -39,22 +37,14 @@ public static BCText get() { /***/ public String gpgNoKeyInLegacySecring; /***/ public String gpgNoPublicKeyFound; /***/ public String gpgNoSecretKeyForPublicKey; - /***/ public String gpgNoSuchAlgorithm; /***/ public String gpgNotASigningKey; /***/ public String gpgKeyInfo; /***/ public String gpgSigningCancelled; + /***/ public String keyAlgorithmMismatch; + /***/ public String keyMismatch; /***/ public String logWarnGnuPGHome; /***/ public String logWarnGpgHomeProperty; /***/ public String nonSignatureError; - /***/ public String secretKeyTooShort; - /***/ public String sexprHexNotClosed; - /***/ public String sexprHexOdd; - /***/ public String sexprStringInvalidEscape; - /***/ public String sexprStringInvalidEscapeAtEnd; - /***/ public String sexprStringInvalidHexEscape; - /***/ public String sexprStringInvalidOctalEscape; - /***/ public String sexprStringNotClosed; - /***/ public String sexprUnhandled; /***/ public String signatureInconsistent; /***/ public String signatureKeyLookupError; /***/ public String signatureNoKeyInfo;
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgPublicKey.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgPublicKey.java index d736536..9ec5b45 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgPublicKey.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgPublicKey.java
@@ -1,3 +1,12 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ package org.eclipse.jgit.gpg.bc.internal; import java.util.List;
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java index 3378bb3..5a3d43b 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifier.java
@@ -12,7 +12,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.security.Security; import java.text.MessageFormat; import java.time.Instant; import java.util.Date; @@ -20,7 +19,6 @@ import java.util.Locale; import org.bouncycastle.bcpg.sig.IssuerFingerprint; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPCompressedData; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; @@ -31,33 +29,20 @@ import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.bouncycastle.util.encoders.Hex; -import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.api.errors.JGitInternalException; -import org.eclipse.jgit.lib.AbstractGpgSignatureVerifier; import org.eclipse.jgit.lib.GpgConfig; -import org.eclipse.jgit.lib.GpgSignatureVerifier; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifier; import org.eclipse.jgit.util.LRUMap; import org.eclipse.jgit.util.StringUtils; /** - * A {@link GpgSignatureVerifier} to verify GPG signatures using BouncyCastle. + * A {@link SignatureVerifier} to verify GPG signatures using BouncyCastle. */ public class BouncyCastleGpgSignatureVerifier - extends AbstractGpgSignatureVerifier { + implements SignatureVerifier { - private static void registerBouncyCastleProviderIfNecessary() { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - } - - /** - * Creates a new instance and registers the BouncyCastle security provider - * if needed. - */ - public BouncyCastleGpgSignatureVerifier() { - registerBouncyCastleProviderIfNecessary(); - } + private static final String NAME = "bc"; //$NON-NLS-1$ // To support more efficient signature verification of multiple objects we // cache public keys once found in a LRU cache. @@ -70,7 +55,7 @@ public BouncyCastleGpgSignatureVerifier() { @Override public String getName() { - return "bc"; //$NON-NLS-1$ + return NAME; } static PGPSignature parseSignature(InputStream in) @@ -90,9 +75,8 @@ static PGPSignature parseSignature(InputStream in) } @Override - public SignatureVerification verify(@NonNull GpgConfig config, byte[] data, - byte[] signatureData) - throws IOException { + public SignatureVerification verify(Repository repository, GpgConfig config, + byte[] data, byte[] signatureData) throws IOException { PGPSignature signature = null; String fingerprint = null; String signer = null; @@ -127,14 +111,15 @@ public SignatureVerification verify(@NonNull GpgConfig config, byte[] data, } Date signatureCreatedAt = signature.getCreationTime(); if (fingerprint == null && signer == null && keyId == null) { - return new VerificationResult(signatureCreatedAt, null, null, null, - false, false, TrustLevel.UNKNOWN, + return new SignatureVerification(NAME, signatureCreatedAt, + null, null, null, false, false, TrustLevel.UNKNOWN, BCText.get().signatureNoKeyInfo); } if (fingerprint != null && keyId != null && !fingerprint.endsWith(keyId)) { - return new VerificationResult(signatureCreatedAt, signer, fingerprint, - signer, false, false, TrustLevel.UNKNOWN, + return new SignatureVerification(NAME, signatureCreatedAt, + signer, fingerprint, signer, false, false, + TrustLevel.UNKNOWN, MessageFormat.format(BCText.get().signatureInconsistent, keyId, fingerprint)); } @@ -175,15 +160,16 @@ public SignatureVerification verify(@NonNull GpgConfig config, byte[] data, bySigner.put(signer, NO_KEY); } } - return new VerificationResult(signatureCreatedAt, signer, - fingerprint, signer, false, false, TrustLevel.UNKNOWN, - BCText.get().signatureNoPublicKey); + return new SignatureVerification(NAME, signatureCreatedAt, + signer, fingerprint, signer, false, false, + TrustLevel.UNKNOWN, BCText.get().signatureNoPublicKey); } if (fingerprint != null && !publicKey.isExactMatch()) { // We did find _some_ signing key for the signer, but it doesn't // match the given fingerprint. - return new VerificationResult(signatureCreatedAt, signer, - fingerprint, signer, false, false, TrustLevel.UNKNOWN, + return new SignatureVerification(NAME, signatureCreatedAt, + signer, fingerprint, signer, false, false, + TrustLevel.UNKNOWN, MessageFormat.format(BCText.get().signatureNoSigningKey, fingerprint)); } @@ -229,8 +215,7 @@ public SignatureVerification verify(@NonNull GpgConfig config, byte[] data, boolean verified = false; try { signature.init( - new JcaPGPContentVerifierBuilderProvider() - .setProvider(BouncyCastleProvider.PROVIDER_NAME), + new JcaPGPContentVerifierBuilderProvider(), pubKey); signature.update(data); verified = signature.verify(); @@ -238,15 +223,8 @@ public SignatureVerification verify(@NonNull GpgConfig config, byte[] data, throw new JGitInternalException( BCText.get().signatureVerificationError, e); } - return new VerificationResult(signatureCreatedAt, signer, fingerprint, user, - verified, expired, trust, null); - } - - @Override - public SignatureVerification verify(byte[] data, byte[] signatureData) - throws IOException { - throw new UnsupportedOperationException( - "Call verify(GpgConfig, byte[], byte[]) instead."); //$NON-NLS-1$ + return new SignatureVerification(NAME, signatureCreatedAt, signer, + fingerprint, user, verified, expired, trust, null); } private TrustLevel parseGpgTrustPacket(byte[] packet) { @@ -282,76 +260,4 @@ public void clear() { byFingerprint.clear(); bySigner.clear(); } - - private static class VerificationResult implements SignatureVerification { - - private final Date creationDate; - - private final String signer; - - private final String keyUser; - - private final String fingerprint; - - private final boolean verified; - - private final boolean expired; - - private final @NonNull TrustLevel trustLevel; - - private final String message; - - public VerificationResult(Date creationDate, String signer, - String fingerprint, String user, boolean verified, - boolean expired, @NonNull TrustLevel trust, String message) { - this.creationDate = creationDate; - this.signer = signer; - this.fingerprint = fingerprint; - this.keyUser = user; - this.verified = verified; - this.expired = expired; - this.trustLevel = trust; - this.message = message; - } - - @Override - public Date getCreationDate() { - return creationDate; - } - - @Override - public String getSigner() { - return signer; - } - - @Override - public String getKeyUser() { - return keyUser; - } - - @Override - public String getKeyFingerprint() { - return fingerprint; - } - - @Override - public boolean isExpired() { - return expired; - } - - @Override - public TrustLevel getTrustLevel() { - return trustLevel; - } - - @Override - public String getMessage() { - return message; - } - - @Override - public boolean getVerified() { - return verified; - } - } }
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java index ae82b75..566ad1b 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignatureVerifierFactory.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.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 @@ -9,20 +9,27 @@ */ package org.eclipse.jgit.gpg.bc.internal; -import org.eclipse.jgit.lib.GpgSignatureVerifier; -import org.eclipse.jgit.lib.GpgSignatureVerifierFactory; +import org.eclipse.jgit.lib.GpgConfig.GpgFormat; +import org.eclipse.jgit.lib.SignatureVerifier; +import org.eclipse.jgit.lib.SignatureVerifierFactory; /** - * A {@link GpgSignatureVerifierFactory} that creates - * {@link GpgSignatureVerifier} instances that verify GPG signatures using - * BouncyCastle and that do cache public keys. + * A {@link SignatureVerifierFactory} that creates {@link SignatureVerifier} + * instances that verify GPG signatures using BouncyCastle and that do cache + * public keys. */ public final class BouncyCastleGpgSignatureVerifierFactory - extends GpgSignatureVerifierFactory { + implements SignatureVerifierFactory { @Override - public GpgSignatureVerifier getVerifier() { + public GpgFormat getType() { + return GpgFormat.OPENPGP; + } + + @Override + public SignatureVerifier create() { return new BouncyCastleGpgSignatureVerifier(); } + }
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 763b7f7..adac9b1 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
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2021, Salesforce and others + * Copyright (C) 2018, 2024, Salesforce and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -14,13 +14,11 @@ 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; 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; @@ -30,79 +28,23 @@ import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException; import org.eclipse.jgit.errors.UnsupportedCredentialItem; -import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.GpgConfig; -import org.eclipse.jgit.lib.GpgObjectSigner; import org.eclipse.jgit.lib.GpgSignature; -import org.eclipse.jgit.lib.GpgSigner; -import org.eclipse.jgit.lib.ObjectBuilder; import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.GpgConfig.GpgFormat; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.Signer; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.util.StringUtils; /** * GPG Signer using the BouncyCastle library. */ -public class BouncyCastleGpgSigner extends GpgSigner - implements GpgObjectSigner { - - private static void registerBouncyCastleProviderIfNecessary() { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - } - - /** - * Create a new instance. - * <p> - * The BounceCastleProvider will be registered if necessary. - * </p> - */ - public BouncyCastleGpgSigner() { - registerBouncyCastleProviderIfNecessary(); - } - - @Override - public boolean canLocateSigningKey(@Nullable String gpgSigningKey, - PersonIdent committer, CredentialsProvider credentialsProvider) - throws CanceledException { - try { - return canLocateSigningKey(gpgSigningKey, committer, - credentialsProvider, null); - } catch (UnsupportedSigningFormatException e) { - // Cannot occur with a null config - return false; - } - } - - @Override - public boolean canLocateSigningKey(@Nullable String gpgSigningKey, - PersonIdent committer, CredentialsProvider credentialsProvider, - GpgConfig config) - throws CanceledException, UnsupportedSigningFormatException { - if (config != null && config.getKeyFormat() != GpgFormat.OPENPGP) { - throw new UnsupportedSigningFormatException( - JGitText.get().onlyOpenPgpSupportedForSigning); - } - try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt( - credentialsProvider)) { - BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey, - committer, passphrasePrompt); - return gpgKey != null; - } catch (CanceledException e) { - throw e; - } catch (Exception e) { - return false; - } - } +public class BouncyCastleGpgSigner implements Signer { private BouncyCastleGpgKey locateSigningKey(@Nullable String gpgSigningKey, PersonIdent committer, @@ -121,38 +63,24 @@ private BouncyCastleGpgKey locateSigningKey(@Nullable String gpgSigningKey, } @Override - public void sign(@NonNull CommitBuilder commit, - @Nullable String gpgSigningKey, @NonNull PersonIdent committer, - CredentialsProvider credentialsProvider) throws CanceledException { - try { - signObject(commit, gpgSigningKey, committer, credentialsProvider, - null); - } catch (UnsupportedSigningFormatException e) { - // Cannot occur with a null config - } - } - - @Override - public void signObject(@NonNull ObjectBuilder object, - @Nullable String gpgSigningKey, @NonNull PersonIdent committer, - CredentialsProvider credentialsProvider, GpgConfig config) - throws CanceledException, UnsupportedSigningFormatException { - if (config != null && config.getKeyFormat() != GpgFormat.OPENPGP) { - throw new UnsupportedSigningFormatException( - JGitText.get().onlyOpenPgpSupportedForSigning); + public GpgSignature sign(Repository repository, GpgConfig config, + byte[] data, PersonIdent committer, String signingKey, + CredentialsProvider credentialsProvider) throws CanceledException, + IOException, UnsupportedSigningFormatException { + String gpgSigningKey = signingKey; + if (gpgSigningKey == null) { + gpgSigningKey = config.getSigningKey(); } try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt( credentialsProvider)) { BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey, - committer, - passphrasePrompt); + committer, passphrasePrompt); PGPSecretKey secretKey = gpgKey.getSecretKey(); if (secretKey == null) { throw new JGitInternalException( BCText.get().unableToSignCommitNoSecretKey); } - JcePBESecretKeyDecryptorBuilder decryptorBuilder = new JcePBESecretKeyDecryptorBuilder() - .setProvider(BouncyCastleProvider.PROVIDER_NAME); + JcePBESecretKeyDecryptorBuilder decryptorBuilder = new JcePBESecretKeyDecryptorBuilder(); PGPPrivateKey privateKey = null; if (!passphrasePrompt.hasPassphrase()) { // Either the key is not encrypted, or it was read from the @@ -177,8 +105,8 @@ public void signObject(@NonNull ObjectBuilder object, PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator( new JcaPGPContentSignerBuilder( publicKey.getAlgorithm(), - HashAlgorithmTags.SHA256).setProvider( - BouncyCastleProvider.PROVIDER_NAME)); + HashAlgorithmTags.SHA256), + publicKey); signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); PGPSignatureSubpacketGenerator subpackets = new PGPSignatureSubpacketGenerator(); subpackets.setIssuerFingerprint(false, publicKey); @@ -202,16 +130,36 @@ public void signObject(@NonNull ObjectBuilder object, ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try (BCPGOutputStream out = new BCPGOutputStream( new ArmoredOutputStream(buffer))) { - signatureGenerator.update(object.build()); + signatureGenerator.update(data); signatureGenerator.generate().encode(out); } - object.setGpgSignature(new GpgSignature(buffer.toByteArray())); - } catch (PGPException | IOException | NoSuchAlgorithmException + return new GpgSignature(buffer.toByteArray()); + } catch (PGPException | NoSuchAlgorithmException | NoSuchProviderException | URISyntaxException e) { throw new JGitInternalException(e.getMessage(), e); } } + @Override + public boolean canLocateSigningKey(Repository repository, GpgConfig config, + PersonIdent committer, String signingKey, + CredentialsProvider credentialsProvider) throws CanceledException { + String gpgSigningKey = signingKey; + if (gpgSigningKey == null) { + gpgSigningKey = config.getSigningKey(); + } + try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt( + credentialsProvider)) { + BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey, + committer, passphrasePrompt); + return gpgKey != null; + } catch (CanceledException e) { + throw e; + } catch (Exception e) { + return false; + } + } + static String extractSignerId(String pgpUserId) { int from = pgpUserId.indexOf('<'); if (from >= 0) {
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignerFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignerFactory.java new file mode 100644 index 0000000..92ab65d --- /dev/null +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSignerFactory.java
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.gpg.bc.internal; + +import org.eclipse.jgit.lib.GpgConfig.GpgFormat; +import org.eclipse.jgit.lib.Signer; +import org.eclipse.jgit.lib.SignerFactory; + +/** + * Factory for creating a {@link Signer} for OPENPGP signatures based on Bouncy + * Castle. + */ +public final class BouncyCastleGpgSignerFactory implements SignerFactory { + + @Override + public GpgFormat getType() { + return GpgFormat.OPENPGP; + } + + @Override + public Signer create() { + return new BouncyCastleGpgSigner(); + } +}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java deleted file mode 100644 index 3924d68..0000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java +++ /dev/null
@@ -1,125 +0,0 @@ -/* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.gpg.bc.internal.keys; - -import java.security.NoSuchAlgorithmException; -import java.text.MessageFormat; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.bouncycastle.util.Arrays; -import org.eclipse.jgit.gpg.bc.internal.BCText; - -/** - * A {@link PBEProtectionRemoverFactory} using AES/OCB/NoPadding for decryption. - * It accepts an AAD in the factory's constructor, so the factory can be used to - * create a {@link PBESecretKeyDecryptor} only for a particular input. - * <p> - * For JGit's needs, this is sufficient, but for a general upstream - * implementation that limitation might not be acceptable. - * </p> - */ -class OCBPBEProtectionRemoverFactory - implements PBEProtectionRemoverFactory { - - private final PGPDigestCalculatorProvider calculatorProvider; - - private final char[] passphrase; - - private final byte[] aad; - - /** - * Creates a new factory instance with the given parameters. - * <p> - * Because the AAD is given at factory level, the {@link PBESecretKeyDecryptor}s - * created by the factory can be used to decrypt only a particular input - * matching this AAD. - * </p> - * - * @param passphrase to use for secret key derivation - * @param calculatorProvider for computing digests - * @param aad for the OCB decryption - */ - OCBPBEProtectionRemoverFactory(char[] passphrase, - PGPDigestCalculatorProvider calculatorProvider, byte[] aad) { - this.calculatorProvider = calculatorProvider; - this.passphrase = passphrase; - this.aad = aad; - } - - @Override - public PBESecretKeyDecryptor createDecryptor(String protection) - throws PGPException { - return new PBESecretKeyDecryptor(passphrase, calculatorProvider) { - - @Override - public byte[] recoverKeyData(int encAlgorithm, byte[] key, - byte[] iv, byte[] encrypted, int encryptedOffset, - int encryptedLength) throws PGPException { - String algorithmName = PGPUtil - .getSymmetricCipherName(encAlgorithm); - byte[] decrypted = null; - try { - // errorprone: "Dynamically constructed transformation - // strings are also flagged, as they may conceal an instance - // of ECB mode." - @SuppressWarnings("InsecureCryptoUsage") - Cipher c = Cipher - .getInstance(algorithmName + "/OCB/NoPadding"); //$NON-NLS-1$ - SecretKey secretKey = new SecretKeySpec(key, algorithmName); - c.init(Cipher.DECRYPT_MODE, secretKey, - new IvParameterSpec(iv)); - c.updateAAD(aad); - decrypted = new byte[c.getOutputSize(encryptedLength)]; - int decryptedLength = c.update(encrypted, encryptedOffset, - encryptedLength, decrypted); - // doFinal() for OCB will check the MAC and throw an - // exception if it doesn't match - decryptedLength += c.doFinal(decrypted, decryptedLength); - if (decryptedLength != decrypted.length) { - throw new PGPException(MessageFormat.format( - BCText.get().cryptWrongDecryptedLength, - Integer.valueOf(decryptedLength), - Integer.valueOf(decrypted.length))); - } - byte[] result = decrypted; - decrypted = null; // Don't clear in finally - return result; - } catch (NoClassDefFoundError e) { - String msg = MessageFormat.format( - BCText.get().gpgNoSuchAlgorithm, - algorithmName + "/OCB"); //$NON-NLS-1$ - throw new PGPException(msg, - new NoSuchAlgorithmException(msg, e)); - } catch (PGPException e) { - throw e; - } catch (Exception e) { - throw new PGPException( - MessageFormat.format(BCText.get().cryptCipherError, - e.getLocalizedMessage()), - e); - } finally { - if (decrypted != null) { - // Prevent halfway decrypted data leaking. - Arrays.fill(decrypted, (byte) 0); - } - } - } - }; - } -} \ No newline at end of file
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java deleted file mode 100644 index fd030ee..0000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java +++ /dev/null
@@ -1,859 +0,0 @@ -/* - * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) - * <p> - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * </p> - * <p> - * The above copyright notice and this permission notice shall be included in all copies or substantial - * portions of the Software. - * </p> - * <p> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * </p> - */ -package org.eclipse.jgit.gpg.bc.internal.keys; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.util.Date; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x9.ECNamedCurveTable; -import org.bouncycastle.bcpg.DSAPublicBCPGKey; -import org.bouncycastle.bcpg.DSASecretBCPGKey; -import org.bouncycastle.bcpg.ECDSAPublicBCPGKey; -import org.bouncycastle.bcpg.ECPublicBCPGKey; -import org.bouncycastle.bcpg.ECSecretBCPGKey; -import org.bouncycastle.bcpg.ElGamalPublicBCPGKey; -import org.bouncycastle.bcpg.ElGamalSecretBCPGKey; -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyPacket; -import org.bouncycastle.bcpg.RSAPublicBCPGKey; -import org.bouncycastle.bcpg.RSASecretBCPGKey; -import org.bouncycastle.bcpg.S2K; -import org.bouncycastle.bcpg.SecretKeyPacket; -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; -import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; - -/** - * A parser for secret keys stored in s-expressions. Original BouncyCastle code - * modified by the JGit team to: - * <ul> - * <li>handle unencrypted DSA, EC, and ElGamal keys (upstream only handles - * unencrypted RSA)</li> - * <li>handle secret keys using AES/OCB as encryption (those don't have a - * hash)</li> - * <li>fix EC parsing to account for "flags" sub-list present for ed25519 and - * curve25519</li> - * <li>add support for ed25519 OIDs unknown to BouncyCastle</li> - * </ul> - */ -@SuppressWarnings("nls") -public class SExprParser { - private final PGPDigestCalculatorProvider digestProvider; - - /** - * Base constructor. - * - * @param digestProvider - * a provider for digest calculations. Used to confirm key - * protection hashes. - */ - public SExprParser(PGPDigestCalculatorProvider digestProvider) { - this.digestProvider = digestProvider; - } - - /** - * Parse a secret key from one of the GPG S expression keys associating it - * with the passed in public key. - * - * @param inputStream - * to read from - * @param keyProtectionRemoverFactory - * for decrypting encrypted keys - * @param pubKey - * the private key should belong to - * - * @return a secret key object. - * @throws IOException - * if an IO error occurred - * @throws PGPException - * if some PGP error occurred - */ - public PGPSecretKey parseSecretKey(InputStream inputStream, - PBEProtectionRemoverFactory keyProtectionRemoverFactory, - PGPPublicKey pubKey) throws IOException, PGPException { - SXprUtils.skipOpenParenthesis(inputStream); - - String type; - - type = SXprUtils.readString(inputStream, inputStream.read()); - if (type.equals("protected-private-key") - || type.equals("private-key")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String keyType = SXprUtils.readString(inputStream, - inputStream.read()); - if (keyType.equals("ecc")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String curveID = SXprUtils.readString(inputStream, - inputStream.read()); - String curveName = SXprUtils.readString(inputStream, - inputStream.read()); - - SXprUtils.skipCloseParenthesis(inputStream); - - byte[] qVal; - - SXprUtils.skipOpenParenthesis(inputStream); - - type = SXprUtils.readString(inputStream, inputStream.read()); - // JGit: c.f. https://github.com/bcgit/bc-java/issues/1590. - // There may be a flags sub-list here for ed25519 or curve25519. - if (type.equals("flags")) { - SXprUtils.readString(inputStream, inputStream.read()); - SXprUtils.skipCloseParenthesis(inputStream); - SXprUtils.skipOpenParenthesis(inputStream); - type = SXprUtils.readString(inputStream, - inputStream.read()); - } - if (type.equals("q")) { - qVal = SXprUtils.readBytes(inputStream, inputStream.read()); - } else { - throw new PGPException("no q value found"); - } - - SXprUtils.skipCloseParenthesis(inputStream); - - BigInteger d = processECSecretKey(inputStream, curveID, - curveName, qVal, keyProtectionRemoverFactory); - - if (curveName.startsWith("NIST ")) { - curveName = curveName.substring("NIST ".length()); - } - - // JGit: BC doesn't know Ed25519 curve name. - ASN1ObjectIdentifier curveOid = ECNamedCurveTable - .getOID(curveName); - if (curveOid == null) { - curveOid = ObjectIds.getByName(curveName); - } - ECPublicBCPGKey basePubKey = new ECDSAPublicBCPGKey( - curveOid, - new BigInteger(1, qVal)); - ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!ObjectIds.match(basePubKey.getCurveOID(), - assocPubKey.getCurveOID()) - || !basePubKey.getEncodedPoint() - .equals(assocPubKey.getEncodedPoint())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - - return new PGPSecretKey( - new SecretKeyPacket(pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new ECSecretBCPGKey(d).getEncoded()), - pubKey); - } else if (keyType.equals("dsa")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger q = readBigInteger("q", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processDSASecretKey(inputStream, p, q, g, y, - keyProtectionRemoverFactory); - - DSAPublicBCPGKey basePubKey = new DSAPublicBCPGKey(p, q, g, y); - DSAPublicBCPGKey assocPubKey = (DSAPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!basePubKey.getP().equals(assocPubKey.getP()) - || !basePubKey.getQ().equals(assocPubKey.getQ()) - || !basePubKey.getG().equals(assocPubKey.getG()) - || !basePubKey.getY().equals(assocPubKey.getY())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - return new PGPSecretKey( - new SecretKeyPacket(pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new DSASecretBCPGKey(x).getEncoded()), - pubKey); - } else if (keyType.equals("elg")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processElGamalSecretKey(inputStream, p, g, y, - keyProtectionRemoverFactory); - - ElGamalPublicBCPGKey basePubKey = new ElGamalPublicBCPGKey(p, g, - y); - ElGamalPublicBCPGKey assocPubKey = (ElGamalPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!basePubKey.getP().equals(assocPubKey.getP()) - || !basePubKey.getG().equals(assocPubKey.getG()) - || !basePubKey.getY().equals(assocPubKey.getY())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - - return new PGPSecretKey( - new SecretKeyPacket(pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new ElGamalSecretBCPGKey(x).getEncoded()), - pubKey); - } else if (keyType.equals("rsa")) { - BigInteger n = readBigInteger("n", inputStream); - BigInteger e = readBigInteger("e", inputStream); - - BigInteger[] values = processRSASecretKey(inputStream, n, e, - keyProtectionRemoverFactory); - - // TODO: type of RSA key? - RSAPublicBCPGKey basePubKey = new RSAPublicBCPGKey(n, e); - RSAPublicBCPGKey assocPubKey = (RSAPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!basePubKey.getModulus().equals(assocPubKey.getModulus()) - || !basePubKey.getPublicExponent() - .equals(assocPubKey.getPublicExponent())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - - return new PGPSecretKey(new SecretKeyPacket( - pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new RSASecretBCPGKey(values[0], values[1], values[2]) - .getEncoded()), - pubKey); - } else { - throw new PGPException("unknown key type: " + keyType); - } - } - - throw new PGPException("unknown key type found"); - } - - /** - * Parse a secret key from one of the GPG S expression keys. - * - * @param inputStream - * to read from - * @param keyProtectionRemoverFactory - * for decrypting encrypted keys - * @param fingerPrintCalculator - * for calculating key fingerprints - * - * @return a secret key object. - * @throws IOException - * if an IO error occurred - * @throws PGPException - * if a PGP error occurred - */ - public PGPSecretKey parseSecretKey(InputStream inputStream, - PBEProtectionRemoverFactory keyProtectionRemoverFactory, - KeyFingerPrintCalculator fingerPrintCalculator) - throws IOException, PGPException { - SXprUtils.skipOpenParenthesis(inputStream); - - String type; - - type = SXprUtils.readString(inputStream, inputStream.read()); - if (type.equals("protected-private-key") - || type.equals("private-key")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String keyType = SXprUtils.readString(inputStream, - inputStream.read()); - if (keyType.equals("ecc")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String curveID = SXprUtils.readString(inputStream, - inputStream.read()); - String curveName = SXprUtils.readString(inputStream, - inputStream.read()); - - if (curveName.startsWith("NIST ")) { - curveName = curveName.substring("NIST ".length()); - } - - SXprUtils.skipCloseParenthesis(inputStream); - - byte[] qVal; - - SXprUtils.skipOpenParenthesis(inputStream); - - type = SXprUtils.readString(inputStream, inputStream.read()); - // JGit: c.f. https://github.com/bcgit/bc-java/issues/1590. - // There may be a flags sub-list here for ed25519 or curve25519. - if (type.equals("flags")) { - SXprUtils.readString(inputStream, inputStream.read()); - SXprUtils.skipCloseParenthesis(inputStream); - SXprUtils.skipOpenParenthesis(inputStream); - type = SXprUtils.readString(inputStream, - inputStream.read()); - } - if (type.equals("q")) { - qVal = SXprUtils.readBytes(inputStream, inputStream.read()); - } else { - throw new PGPException("no q value found"); - } - - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.ECDSA, new Date(), - new ECDSAPublicBCPGKey( - ECNamedCurveTable.getOID(curveName), - new BigInteger(1, qVal))); - - SXprUtils.skipCloseParenthesis(inputStream); - - BigInteger d = processECSecretKey(inputStream, curveID, - curveName, qVal, keyProtectionRemoverFactory); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new ECSecretBCPGKey(d).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else if (keyType.equals("dsa")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger q = readBigInteger("q", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processDSASecretKey(inputStream, p, q, g, y, - keyProtectionRemoverFactory); - - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.DSA, new Date(), - new DSAPublicBCPGKey(p, q, g, y)); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new DSASecretBCPGKey(x).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else if (keyType.equals("elg")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processElGamalSecretKey(inputStream, p, g, y, - keyProtectionRemoverFactory); - - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, new Date(), - new ElGamalPublicBCPGKey(p, g, y)); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new ElGamalSecretBCPGKey(x).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else if (keyType.equals("rsa")) { - BigInteger n = readBigInteger("n", inputStream); - BigInteger e = readBigInteger("e", inputStream); - - BigInteger[] values = processRSASecretKey(inputStream, n, e, - keyProtectionRemoverFactory); - - // TODO: type of RSA key? - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.RSA_GENERAL, new Date(), - new RSAPublicBCPGKey(n, e)); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new RSASecretBCPGKey(values[0], values[1], - values[2]).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else { - throw new PGPException("unknown key type: " + keyType); - } - } - - throw new PGPException("unknown key type found"); - } - - private BigInteger readBigInteger(String expectedType, - InputStream inputStream) throws IOException, PGPException { - SXprUtils.skipOpenParenthesis(inputStream); - - String type = SXprUtils.readString(inputStream, inputStream.read()); - if (!type.equals(expectedType)) { - throw new PGPException(expectedType + " value expected"); - } - - byte[] nBytes = SXprUtils.readBytes(inputStream, inputStream.read()); - BigInteger v = new BigInteger(1, nBytes); - - SXprUtils.skipCloseParenthesis(inputStream); - - return v; - } - - private static byte[][] extractData(InputStream inputStream, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws PGPException, IOException { - byte[] data; - byte[] protectedAt = null; - - SXprUtils.skipOpenParenthesis(inputStream); - - String type = SXprUtils.readString(inputStream, inputStream.read()); - if (type.equals("protected")) { - String protection = SXprUtils.readString(inputStream, - inputStream.read()); - - SXprUtils.skipOpenParenthesis(inputStream); - - S2K s2k = SXprUtils.parseS2K(inputStream); - - byte[] iv = SXprUtils.readBytes(inputStream, inputStream.read()); - - SXprUtils.skipCloseParenthesis(inputStream); - - byte[] secKeyData = SXprUtils.readBytes(inputStream, - inputStream.read()); - - SXprUtils.skipCloseParenthesis(inputStream); - - PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory - .createDecryptor(protection); - - // TODO: recognise other algorithms - byte[] key = keyDecryptor.makeKeyFromPassPhrase( - SymmetricKeyAlgorithmTags.AES_128, s2k); - - data = keyDecryptor.recoverKeyData( - SymmetricKeyAlgorithmTags.AES_128, key, iv, secKeyData, 0, - secKeyData.length); - - // check if protected at is present - if (inputStream.read() == '(') { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - bOut.write('('); - int ch; - while ((ch = inputStream.read()) >= 0 && ch != ')') { - bOut.write(ch); - } - - if (ch != ')') { - throw new IOException("unexpected end to SExpr"); - } - - bOut.write(')'); - - protectedAt = bOut.toByteArray(); - } - - SXprUtils.skipCloseParenthesis(inputStream); - SXprUtils.skipCloseParenthesis(inputStream); - } else if (type.equals("d") || type.equals("x")) { - // JGit modification: unencrypted DSA or ECC keys can have an "x" - // here - return null; - } else { - throw new PGPException("protected block not found"); - } - - return new byte[][] { data, protectedAt }; - } - - private BigInteger processDSASecretKey(InputStream inputStream, - BigInteger p, BigInteger q, BigInteger g, BigInteger y, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - // JGit modification: handle unencrypted DSA keys - if (basicData == null) { - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - BigInteger x = new BigInteger(1, nBytes); - SXprUtils.skipCloseParenthesis(inputStream); - return x; - } - - byte[] keyData = basicData[0]; - byte[] protectedAt = basicData[1]; - - // - // parse the secret key S-expr - // - InputStream keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - - BigInteger x = readBigInteger("x", keyIn); - - SXprUtils.skipCloseParenthesis(keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return x; - } - - SXprUtils.skipOpenParenthesis(keyIn); - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:dsa")); - writeCanonical(dOut, "p", p); - writeCanonical(dOut, "q", q); - writeCanonical(dOut, "g", g); - writeCanonical(dOut, "y", y); - writeCanonical(dOut, "x", x); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return x; - } - - private BigInteger processElGamalSecretKey(InputStream inputStream, - BigInteger p, BigInteger g, BigInteger y, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - // JGit modification: handle unencrypted EC keys - if (basicData == null) { - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - BigInteger x = new BigInteger(1, nBytes); - SXprUtils.skipCloseParenthesis(inputStream); - return x; - } - - byte[] keyData = basicData[0]; - byte[] protectedAt = basicData[1]; - - // - // parse the secret key S-expr - // - InputStream keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - - BigInteger x = readBigInteger("x", keyIn); - - SXprUtils.skipCloseParenthesis(keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return x; - } - - SXprUtils.skipOpenParenthesis(keyIn); - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:elg")); - writeCanonical(dOut, "p", p); - writeCanonical(dOut, "g", g); - writeCanonical(dOut, "y", y); - writeCanonical(dOut, "x", x); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return x; - } - - private BigInteger processECSecretKey(InputStream inputStream, - String curveID, String curveName, byte[] qVal, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - // JGit modification: handle unencrypted EC keys - if (basicData == null) { - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - BigInteger d = new BigInteger(1, nBytes); - SXprUtils.skipCloseParenthesis(inputStream); - return d; - } - - byte[] keyData = basicData[0]; - byte[] protectedAt = basicData[1]; - - // - // parse the secret key S-expr - // - InputStream keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - BigInteger d = readBigInteger("d", keyIn); - SXprUtils.skipCloseParenthesis(keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return d; - } - - SXprUtils.skipOpenParenthesis(keyIn); - - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:ecc")); - - dOut.write(Strings.toByteArray("(" + curveID.length() + ":" - + curveID + curveName.length() + ":" + curveName + ")")); - - writeCanonical(dOut, "q", qVal); - writeCanonical(dOut, "d", d); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return d; - } - - private BigInteger[] processRSASecretKey(InputStream inputStream, - BigInteger n, BigInteger e, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - byte[] keyData; - byte[] protectedAt = null; - - InputStream keyIn; - BigInteger d; - - if (basicData == null) { - keyIn = inputStream; - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - d = new BigInteger(1, nBytes); - - SXprUtils.skipCloseParenthesis(inputStream); - - } else { - keyData = basicData[0]; - protectedAt = basicData[1]; - - keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - d = readBigInteger("d", keyIn); - } - - // - // parse the secret key S-expr - // - - BigInteger p = readBigInteger("p", keyIn); - BigInteger q = readBigInteger("q", keyIn); - BigInteger u = readBigInteger("u", keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (basicData == null - || keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return new BigInteger[] { d, p, q, u }; - } - - SXprUtils.skipCloseParenthesis(keyIn); - - SXprUtils.skipOpenParenthesis(keyIn); - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:rsa")); - - writeCanonical(dOut, "n", n); - writeCanonical(dOut, "e", e); - writeCanonical(dOut, "d", d); - writeCanonical(dOut, "p", p); - writeCanonical(dOut, "q", q); - writeCanonical(dOut, "u", u); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return new BigInteger[] { d, p, q, u }; - } - - private void writeCanonical(OutputStream dOut, String label, BigInteger i) - throws IOException { - writeCanonical(dOut, label, i.toByteArray()); - } - - private void writeCanonical(OutputStream dOut, String label, byte[] data) - throws IOException { - dOut.write(Strings.toByteArray( - "(" + label.length() + ":" + label + data.length + ":")); - dOut.write(data); - dOut.write(Strings.toByteArray(")")); - } -}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java deleted file mode 100644 index 220aa28..0000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java +++ /dev/null
@@ -1,110 +0,0 @@ -/* - * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) - * <p> - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * </p> - * <p> - * The above copyright notice and this permission notice shall be included in all copies or substantial - * portions of the Software. - * </p> - * <p> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * </p> - */ -package org.eclipse.jgit.gpg.bc.internal.keys; - -// This class is an unmodified copy from Bouncy Castle; needed because it's package-visible only and used by SExprParser. - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.S2K; -import org.bouncycastle.util.io.Streams; - -/** - * Utility functions for looking a S-expression keys. This class will move when - * it finds a better home! - * <p> - * Format documented here: - * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master - * </p> - */ -class SXprUtils { - private static int readLength(InputStream in, int ch) throws IOException { - int len = ch - '0'; - - while ((ch = in.read()) >= 0 && ch != ':') { - len = len * 10 + ch - '0'; - } - - return len; - } - - static String readString(InputStream in, int ch) throws IOException { - int len = readLength(in, ch); - - char[] chars = new char[len]; - - for (int i = 0; i != chars.length; i++) { - chars[i] = (char) in.read(); - } - - return new String(chars); - } - - static byte[] readBytes(InputStream in, int ch) throws IOException { - int len = readLength(in, ch); - - byte[] data = new byte[len]; - - Streams.readFully(in, data); - - return data; - } - - static S2K parseS2K(InputStream in) throws IOException { - skipOpenParenthesis(in); - - // Algorithm is hard-coded to SHA1 below anyway. - readString(in, in.read()); - byte[] iv = readBytes(in, in.read()); - final long iterationCount = Long.parseLong(readString(in, in.read())); - - skipCloseParenthesis(in); - - // we have to return the actual iteration count provided. - S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, (int) iterationCount) { - @Override - public long getIterationCount() { - return iterationCount; - } - }; - - return s2k; - } - - static void skipOpenParenthesis(InputStream in) throws IOException { - int ch = in.read(); - if (ch != '(') { - throw new IOException( - "unknown character encountered: " + (char) ch); //$NON-NLS-1$ - } - } - - static void skipCloseParenthesis(InputStream in) throws IOException { - int ch = in.read(); - if (ch != ')') { - throw new IOException("unknown character encountered"); //$NON-NLS-1$ - } - } -}
diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java index a659d38..a56e418 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.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 @@ -9,34 +9,36 @@ */ package org.eclipse.jgit.gpg.bc.internal.keys; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; +import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.StreamCorruptedException; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.text.MessageFormat; -import java.util.Arrays; +import org.bouncycastle.bcpg.ECPublicBCPGKey; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.gpg.PGPSecretKeyParser; +import org.bouncycastle.gpg.SExprParser; +import org.bouncycastle.openpgp.OpenedPGPKeyData; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory; -import org.bouncycastle.util.io.Streams; import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.errors.UnsupportedCredentialItem; import org.eclipse.jgit.gpg.bc.internal.BCText; -import org.eclipse.jgit.util.RawParseUtils; /** * Utilities for reading GPG secret keys from a gpg-agent key file. */ public final class SecretKeys { + // Maximum nesting depth of sub-lists in an S-Expression for a secret key. + private static final int MAX_SEXPR_NESTING = 20; + private SecretKeys() { // No instantiation. } @@ -64,12 +66,6 @@ public interface PassphraseSupplier { UnsupportedCredentialItem, URISyntaxException; } - private static final byte[] PROTECTED_KEY = "protected-private-key" //$NON-NLS-1$ - .getBytes(StandardCharsets.US_ASCII); - - private static final byte[] OCB_PROTECTED = "openpgp-s2k3-ocb-aes" //$NON-NLS-1$ - .getBytes(StandardCharsets.US_ASCII); - /** * Reads a GPG secret key from the given stream. * @@ -99,500 +95,59 @@ public static PGPSecretKey readSecretKey(InputStream in, PassphraseSupplier passphraseSupplier, PGPPublicKey publicKey) throws IOException, PGPException, CanceledException, UnsupportedCredentialItem, URISyntaxException { - byte[] data = Streams.readAll(in); - if (data.length == 0) { - throw new EOFException(); - } else if (data.length < 4 + PROTECTED_KEY.length) { - // +4 for "(21:" for a binary protected key - throw new IOException( - MessageFormat.format(BCText.get().secretKeyTooShort, - Integer.toUnsignedString(data.length))); + OpenedPGPKeyData data; + try (InputStream keyIn = new BufferedInputStream(in)) { + data = PGPSecretKeyParser.parse(keyIn, MAX_SEXPR_NESTING); } - SExprParser parser = new SExprParser(calculatorProvider); - byte firstChar = data[0]; - try { - if (firstChar == '(') { - // Binary format. - PBEProtectionRemoverFactory decryptor = null; - if (matches(data, 4, PROTECTED_KEY)) { - // AES/CBC encrypted. - decryptor = new JcePBEProtectionRemoverFactory( - passphraseSupplier.getPassphrase(), - calculatorProvider); - } - try (InputStream sIn = new ByteArrayInputStream(data)) { - return parser.parseSecretKey(sIn, decryptor, publicKey); - } - } - // Assume it's the new key-value format. - try (ByteArrayInputStream keyIn = new ByteArrayInputStream(data)) { - byte[] rawData = keyFromNameValueFormat(keyIn); - if (!matches(rawData, 1, PROTECTED_KEY)) { - // Not encrypted human-readable format. - try (InputStream sIn = new ByteArrayInputStream( - convertSexpression(rawData))) { - return parser.parseSecretKey(sIn, null, publicKey); - } - } - // An encrypted key from a key-value file. Most likely AES/OCB - // encrypted. - boolean isOCB[] = { false }; - byte[] sExp = convertSexpression(rawData, isOCB); - PBEProtectionRemoverFactory decryptor; - if (isOCB[0]) { - decryptor = new OCBPBEProtectionRemoverFactory( - passphraseSupplier.getPassphrase(), - calculatorProvider, getAad(sExp)); - } else { - decryptor = new JcePBEProtectionRemoverFactory( - passphraseSupplier.getPassphrase(), - calculatorProvider); - } - try (InputStream sIn = new ByteArrayInputStream(sExp)) { - return parser.parseSecretKey(sIn, decryptor, publicKey); - } - } - } catch (IOException e) { - throw new PGPException(e.getLocalizedMessage(), e); + PBEProtectionRemoverFactory decryptor = null; + if (isProtected(data)) { + decryptor = new JcePBEProtectionRemoverFactory( + passphraseSupplier.getPassphrase(), calculatorProvider); } - } - - /** - * Extract the AAD for the OCB decryption from an s-expression. - * - * @param sExp - * buffer containing a valid binary s-expression - * @return the AAD - */ - private static byte[] getAad(byte[] sExp) { - // Given a key - // @formatter:off - // (protected-private-key (rsa ... (protected openpgp-s2k3-ocb-aes ... )(protected-at ...))) - // A B C D - // The AAD is [A..B)[C..D). (From the binary serialized form.) - // @formatter:on - int i = 1; // Skip initial '(' - while (sExp[i] != '(') { - i++; - } - int aadStart = i++; - int aadEnd = skip(sExp, aadStart); - byte[] protectedPrefix = "(9:protected" //$NON-NLS-1$ - .getBytes(StandardCharsets.US_ASCII); - while (!matches(sExp, i, protectedPrefix)) { - i++; - } - int protectedStart = i; - int protectedEnd = skip(sExp, protectedStart); - byte[] aadData = new byte[aadEnd - aadStart - - (protectedEnd - protectedStart)]; - System.arraycopy(sExp, aadStart, aadData, 0, protectedStart - aadStart); - System.arraycopy(sExp, protectedEnd, aadData, protectedStart - aadStart, - aadEnd - protectedEnd); - return aadData; - } - - /** - * Skips a list including nested lists. - * - * @param sExp - * buffer containing valid binary s-expression data - * @param start - * index of the opening '(' of the list to skip - * @return the index after the closing ')' of the skipped list - */ - private static int skip(byte[] sExp, int start) { - int i = start + 1; - int depth = 1; - while (depth > 0) { - switch (sExp[i]) { - case '(': - depth++; - break; - case ')': - depth--; - break; - default: - // We must be on a length - int j = i; - while (sExp[j] >= '0' && sExp[j] <= '9') { - j++; - } - // j is on the colon - int length = Integer.parseInt( - new String(sExp, i, j - i, StandardCharsets.US_ASCII)); - i = j + length; + switch (publicKey.getAlgorithm()) { + case PublicKeyAlgorithmTags.EDDSA_LEGACY: + case PublicKeyAlgorithmTags.Ed25519: + // If we let Bouncy Castle check whether the secret key matches the + // given public key it may get into trouble in some cases with + // ed25519 keys. It appears that we may end up with secret keys + // using the official RFC 8410 OID for ed25519, "1.3.101.112", while + // the public key passed in may have a non-standard OpenPGP-specific + // OID "1.3.6.1.4.1.11591.15.1", or vice versa. Bouncy Castle then + // throws an exception because of the different OIDs. + // + // The work-around is to just read the secret key, and double-check + // later that the OIDs are compatible and the curve points match. + PGPSecretKey secret = data.getKeyData(null, calculatorProvider, + decryptor, new JcaKeyFingerprintCalculator(), + MAX_SEXPR_NESTING); + PGPPublicKey pubKeyRead = secret.getPublicKey(); + int algoRead = pubKeyRead.getAlgorithm(); + if (algoRead != PublicKeyAlgorithmTags.EDDSA_LEGACY + && algoRead != PublicKeyAlgorithmTags.Ed25519) { + throw new PGPException(BCText.get().keyAlgorithmMismatch); } - i++; - } - return i; - } - - /** - * Checks whether the {@code needle} matches {@code src} at offset - * {@code from}. - * - * @param src - * to match against {@code needle} - * @param from - * position in {@code src} to start matching - * @param needle - * to match against - * @return {@code true} if {@code src} contains {@code needle} at position - * {@code from}, {@code false} otherwise - */ - private static boolean matches(byte[] src, int from, byte[] needle) { - if (from < 0 || from + needle.length > src.length) { - return false; - } - return org.bouncycastle.util.Arrays.constantTimeAreEqual(needle.length, - src, from, needle, 0); - } - - /** - * Converts a human-readable serialized s-expression into a binary - * serialized s-expression. - * - * @param humanForm - * to convert - * @return the converted s-expression - * @throws IOException - * if the conversion fails - */ - private static byte[] convertSexpression(byte[] humanForm) - throws IOException { - boolean[] isOCB = { false }; - return convertSexpression(humanForm, isOCB); - } - - /** - * Converts a human-readable serialized s-expression into a binary - * serialized s-expression. - * - * @param humanForm - * to convert - * @param isOCB - * returns whether the s-expression specified AES/OCB encryption - * @return the converted s-expression - * @throws IOException - * if the conversion fails - */ - private static byte[] convertSexpression(byte[] humanForm, boolean[] isOCB) - throws IOException { - int pos = 0; - try (ByteArrayOutputStream out = new ByteArrayOutputStream( - humanForm.length)) { - while (pos < humanForm.length) { - byte b = humanForm[pos]; - if (b == '(' || b == ')') { - out.write(b); - pos++; - } else if (isGpgSpace(b)) { - pos++; - } else if (b == '#') { - // Hex value follows up to the next # - int i = ++pos; - while (i < humanForm.length && isHex(humanForm[i])) { - i++; - } - if (i == pos || humanForm[i] != '#') { - throw new StreamCorruptedException( - BCText.get().sexprHexNotClosed); - } - if ((i - pos) % 2 != 0) { - throw new StreamCorruptedException( - BCText.get().sexprHexOdd); - } - int l = (i - pos) / 2; - out.write(Integer.toString(l) - .getBytes(StandardCharsets.US_ASCII)); - out.write(':'); - while (pos < i) { - int x = (nibble(humanForm[pos]) << 4) - | nibble(humanForm[pos + 1]); - pos += 2; - out.write(x); - } - pos = i + 1; - } else if (isTokenChar(b)) { - // Scan the token - int start = pos++; - while (pos < humanForm.length - && isTokenChar(humanForm[pos])) { - pos++; - } - int l = pos - start; - if (pos - start == OCB_PROTECTED.length - && matches(humanForm, start, OCB_PROTECTED)) { - isOCB[0] = true; - } - out.write(Integer.toString(l) - .getBytes(StandardCharsets.US_ASCII)); - out.write(':'); - out.write(humanForm, start, pos - start); - } else if (b == '"') { - // Potentially quoted string. - int start = ++pos; - boolean escaped = false; - while (pos < humanForm.length - && (escaped || humanForm[pos] != '"')) { - int ch = humanForm[pos++]; - escaped = !escaped && ch == '\\'; - } - if (pos >= humanForm.length) { - throw new StreamCorruptedException( - BCText.get().sexprStringNotClosed); - } - // start is on the first character of the string, pos on the - // closing quote. - byte[] dq = dequote(humanForm, start, pos); - out.write(Integer.toString(dq.length) - .getBytes(StandardCharsets.US_ASCII)); - out.write(':'); - out.write(dq); - pos++; - } else { - throw new StreamCorruptedException( - MessageFormat.format(BCText.get().sexprUnhandled, - Integer.toHexString(b & 0xFF))); - } + ECPublicBCPGKey ec1 = (ECPublicBCPGKey) publicKey + .getPublicKeyPacket().getKey(); + ECPublicBCPGKey ec2 = (ECPublicBCPGKey) pubKeyRead + .getPublicKeyPacket().getKey(); + if (!ObjectIds.match(ec1.getCurveOID(), ec2.getCurveOID()) + || !ec1.getEncodedPoint().equals(ec2.getEncodedPoint())) { + throw new PGPException( + MessageFormat.format(BCText.get().keyMismatch, + ec1.getCurveOID(), ec1.getEncodedPoint(), + ec2.getCurveOID(), ec2.getEncodedPoint())); } - return out.toByteArray(); - } - } - - /** - * GPG-style string de-quoting, which is basically C-style, with some - * literal CR/LF escaping. - * - * @param in - * buffer containing the quoted string - * @param from - * index after the opening quote in {@code in} - * @param to - * index of the closing quote in {@code in} - * @return the dequoted raw string value - * @throws StreamCorruptedException - * if object stream is corrupt - */ - private static byte[] dequote(byte[] in, int from, int to) - throws StreamCorruptedException { - // Result must be shorter or have the same length - byte[] out = new byte[to - from]; - int j = 0; - int i = from; - while (i < to) { - byte b = in[i++]; - if (b != '\\') { - out[j++] = b; - continue; - } - if (i == to) { - throw new StreamCorruptedException( - BCText.get().sexprStringInvalidEscapeAtEnd); - } - b = in[i++]; - switch (b) { - case 'b': - out[j++] = '\b'; - break; - case 'f': - out[j++] = '\f'; - break; - case 'n': - out[j++] = '\n'; - break; - case 'r': - out[j++] = '\r'; - break; - case 't': - out[j++] = '\t'; - break; - case 'v': - out[j++] = 0x0B; - break; - case '"': - case '\'': - case '\\': - out[j++] = b; - break; - case '\r': - // Escaped literal line end. If an LF is following, skip that, - // too. - if (i < to && in[i] == '\n') { - i++; - } - break; - case '\n': - // Same for LF possibly followed by CR. - if (i < to && in[i] == '\r') { - i++; - } - break; - case 'x': - if (i + 1 >= to || !isHex(in[i]) || !isHex(in[i + 1])) { - throw new StreamCorruptedException( - BCText.get().sexprStringInvalidHexEscape); - } - out[j++] = (byte) ((nibble(in[i]) << 4) | nibble(in[i + 1])); - i += 2; - break; - case '0': - case '1': - case '2': - case '3': - if (i + 2 >= to || !isOctal(in[i]) || !isOctal(in[i + 1]) - || !isOctal(in[i + 2])) { - throw new StreamCorruptedException( - BCText.get().sexprStringInvalidOctalEscape); - } - out[j++] = (byte) (((((in[i] - '0') << 3) - | (in[i + 1] - '0')) << 3) | (in[i + 2] - '0')); - i += 3; - break; - default: - throw new StreamCorruptedException(MessageFormat.format( - BCText.get().sexprStringInvalidEscape, - Integer.toHexString(b & 0xFF))); - } - } - return Arrays.copyOf(out, j); - } - - /** - * Extracts the key from a GPG name-value-pair key file. - * <p> - * Package-visible for tests only. - * </p> - * - * @param in - * {@link InputStream} to read from; should be buffered - * @return the raw key data as extracted from the file - * @throws IOException - * if the {@code in} stream cannot be read or does not contain a - * key - */ - static byte[] keyFromNameValueFormat(InputStream in) throws IOException { - // It would be nice if we could use RawParseUtils here, but GPG compares - // names case-insensitively. We're only interested in the "Key:" - // name-value pair. - int[] nameLow = { 'k', 'e', 'y', ':' }; - int[] nameCap = { 'K', 'E', 'Y', ':' }; - int nameIdx = 0; - for (;;) { - int next = in.read(); - if (next < 0) { - throw new EOFException(); - } - if (next == '\n') { - nameIdx = 0; - } else if (nameIdx >= 0) { - if (nameLow[nameIdx] == next || nameCap[nameIdx] == next) { - nameIdx++; - if (nameIdx == nameLow.length) { - break; - } - } else { - nameIdx = -1; - } - } - } - // We're after "Key:". Read the value as continuation lines. - int last = ':'; - byte[] rawData; - try (ByteArrayOutputStream out = new ByteArrayOutputStream(8192)) { - for (;;) { - int next = in.read(); - if (next < 0) { - break; - } - if (last == '\n') { - if (next == ' ' || next == '\t') { - // Continuation line; skip this whitespace - last = next; - continue; - } - break; // Not a continuation line - } - out.write(next); - last = next; - } - rawData = out.toByteArray(); - } - // GPG trims off trailing whitespace, and a line having only whitespace - // is a single LF. - try (ByteArrayOutputStream out = new ByteArrayOutputStream( - rawData.length)) { - int lineStart = 0; - boolean trimLeading = true; - while (lineStart < rawData.length) { - int nextLineStart = RawParseUtils.nextLF(rawData, lineStart); - if (trimLeading) { - while (lineStart < nextLineStart - && isGpgSpace(rawData[lineStart])) { - lineStart++; - } - } - // Trim trailing - int i = nextLineStart - 1; - while (lineStart < i && isGpgSpace(rawData[i])) { - i--; - } - if (i <= lineStart) { - // Empty line signifies LF - out.write('\n'); - trimLeading = true; - } else { - out.write(rawData, lineStart, i - lineStart + 1); - trimLeading = false; - } - lineStart = nextLineStart; - } - return out.toByteArray(); - } - } - - private static boolean isGpgSpace(int ch) { - return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; - } - - private static boolean isTokenChar(int ch) { - switch (ch) { - case '-': - case '.': - case '/': - case '_': - case ':': - case '*': - case '+': - case '=': - return true; + return secret; default: - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') - || (ch >= '0' && ch <= '9')) { - return true; - } - return false; + // For other key types let Bouncy Castle do the check. + return data.getKeyData(publicKey, calculatorProvider, decryptor, + null, MAX_SEXPR_NESTING); } } - private static boolean isHex(int ch) { - return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') - || (ch >= 'a' && ch <= 'f'); + private static boolean isProtected(OpenedPGPKeyData data) { + return SExprParser.ProtectionFormatTypeTags.PROTECTED_PRIVATE_KEY == SExprParser + .getProtectionType(data.getKeyExpression().getString(0)); } - private static boolean isOctal(int ch) { - return (ch >= '0' && ch <= '7'); - } - - private static int nibble(int ch) { - if (ch >= '0' && ch <= '9') { - return ch - '0'; - } else if (ch >= 'A' && ch <= 'F') { - return ch - 'A' + 10; - } else if (ch >= 'a' && ch <= 'f') { - return ch - 'a' + 10; - } - return -1; - } }
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF index c1ec7ae..244b20a 100644 --- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.apache Bundle-SymbolicName: org.eclipse.jgit.http.apache -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor @@ -26,11 +26,11 @@ org.apache.http.impl.conn;version="[4.4.0,5.0.0)", org.apache.http.params;version="[4.3.0,5.0.0)", org.apache.http.ssl;version="[4.3.0,5.0.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)" -Export-Package: org.eclipse.jgit.transport.http.apache;version="7.0.0"; + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)" +Export-Package: org.eclipse.jgit.transport.http.apache;version="7.3.0"; uses:="org.apache.http.client, org.eclipse.jgit.transport.http, org.apache.http.entity,
diff --git a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF index d29d387..86adeb6 100644 --- a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.http.apache - Sources Bundle-SymbolicName: org.eclipse.jgit.http.apache.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml index 51a79d6..0c7c5ff 100644 --- a/org.eclipse.jgit.http.apache/pom.xml +++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -15,7 +15,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.apache</artifactId>
diff --git a/org.eclipse.jgit.http.server/BUILD b/org.eclipse.jgit.http.server/BUILD index f8aa44d..a0dae48 100644 --- a/org.eclipse.jgit.http.server/BUILD +++ b/org.eclipse.jgit.http.server/BUILD
@@ -2,11 +2,16 @@ package(default_visibility = ["//visibility:public"]) +filegroup( + name = "jgit-servlet-resources", + srcs = glob(["resources/**"]), +) + java_library( name = "jgit-servlet", srcs = glob(["src/**/*.java"]), resource_strip_prefix = "org.eclipse.jgit.http.server/resources", - resources = glob(["resources/**"]), + resources = [":jgit-servlet-resources"], deps = [ "//lib:servlet-api", # We want these deps to be provided_deps
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index 124129d..71c471d 100644 --- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.server Bundle-SymbolicName: org.eclipse.jgit.http.server -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.http.server;version="7.0.0", - org.eclipse.jgit.http.server.glue;version="7.0.0"; +Export-Package: org.eclipse.jgit.http.server;version="7.3.0", + org.eclipse.jgit.http.server.glue;version="7.3.0"; uses:="jakarta.servlet, jakarta.servlet.http", - org.eclipse.jgit.http.server.resolver;version="7.0.0"; + org.eclipse.jgit.http.server.resolver;version="7.3.0"; uses:="jakarta.servlet.http org.eclipse.jgit.transport.resolver, org.eclipse.jgit.lib, @@ -19,14 +19,14 @@ Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", jakarta.servlet.http;version="[6.0.0,7.0.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.parser;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.resolver;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)" + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.parser;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.resolver;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)"
diff --git a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF index bbb29cd..67a14cf 100644 --- a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.http.server - Sources Bundle-SymbolicName: org.eclipse.jgit.http.server.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index 7645dd1..b34ca2f 100644 --- a/org.eclipse.jgit.http.server/pom.xml +++ b/org.eclipse.jgit.http.server/pom.xml
@@ -19,7 +19,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.server</artifactId>
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java index d2f0cd2..bf3da4b 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -255,9 +255,11 @@ private static void writePacket(PacketLineOut pckOut, String textForGit) private static void send(HttpServletRequest req, HttpServletResponse res, String type, byte[] buf, int httpStatus) throws IOException { ServletUtils.consumeRequestBody(req); - res.setStatus(httpStatus); - res.setContentType(type); - res.setContentLength(buf.length); + if (!res.isCommitted()) { + res.setStatus(httpStatus); + res.setContentType(type); + res.setContentLength(buf.length); + } try (OutputStream os = res.getOutputStream()) { os.write(buf); }
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index edce2d8..518afb3 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.test Bundle-SymbolicName: org.eclipse.jgit.http.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -29,26 +29,26 @@ org.eclipse.jetty.util.component;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.security;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.thread;version="[12.0.0,13.0.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.http.server;version="[7.0.0,7.1.0)", - org.eclipse.jgit.http.server.glue;version="[7.0.0,7.1.0)", - org.eclipse.jgit.http.server.resolver;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http.apache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.resolver;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.http.server;version="[7.3.0,7.4.0)", + org.eclipse.jgit.http.server.glue;version="[7.3.0,7.4.0)", + org.eclipse.jgit.http.server.resolver;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http.apache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.resolver;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.rules;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml index 01ee782..8ed3017 100644 --- a/org.eclipse.jgit.http.test/pom.xml +++ b/org.eclipse.jgit.http.test/pom.xml
@@ -18,7 +18,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 850e895..b0d17ad 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -1728,7 +1728,8 @@ public void testPush_CreateBranch() throws Exception { assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId()); fsck(remoteRepository, Q); - final ReflogReader log = remoteRepository.getReflogReader(dstName); + final ReflogReader log = remoteRepository.getRefDatabase() + .getReflogReader(dstName); assertNotNull("has log for " + dstName, log); final ReflogEntry last = log.getLastEntry();
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index 3e98351..e3a6e26 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit.http Bundle-SymbolicName: org.eclipse.jgit.junit.http -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy @@ -22,17 +22,17 @@ org.eclipse.jetty.util.component;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.security;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.ssl;version="[12.0.0,13.0.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.http.server;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.resolver;version="[7.0.0,7.1.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.http.server;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.resolver;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.slf4j.helpers;version="[1.7.0,3.0.0)" -Export-Package: org.eclipse.jgit.junit.http;version="7.0.0"; +Export-Package: org.eclipse.jgit.junit.http;version="7.3.0"; uses:="org.eclipse.jgit.transport, jakarta.servlet, jakarta.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF index cfeb426..855f210 100644 --- a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.junit.http - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.http.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index 67c8265..2947f21 100644 --- a/org.eclipse.jgit.junit.http/pom.xml +++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF index 424bac1..30c359b 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF
@@ -3,46 +3,46 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit.ssh Bundle-SymbolicName: org.eclipse.jgit.junit.ssh -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.apache.sshd.common;version="[2.12.0,2.13.0)", - org.apache.sshd.common.config.keys;version="[2.12.0,2.13.0)", - org.apache.sshd.common.file.virtualfs;version="[2.12.0,2.13.0)", - org.apache.sshd.common.helpers;version="[2.12.0,2.13.0)", - org.apache.sshd.common.io;version="[2.12.0,2.13.0)", - org.apache.sshd.common.kex;version="[2.12.0,2.13.0)", - org.apache.sshd.common.keyprovider;version="[2.12.0,2.13.0)", - org.apache.sshd.common.session;version="[2.12.0,2.13.0)", - org.apache.sshd.common.signature;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.buffer;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.logging;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.security;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.threads;version="[2.12.0,2.13.0)", - org.apache.sshd.core;version="[2.12.0,2.13.0)", - org.apache.sshd.server;version="[2.12.0,2.13.0)", - org.apache.sshd.server.auth;version="[2.12.0,2.13.0)", - org.apache.sshd.server.auth.gss;version="[2.12.0,2.13.0)", - org.apache.sshd.server.auth.keyboard;version="[2.12.0,2.13.0)", - org.apache.sshd.server.auth.password;version="[2.12.0,2.13.0)", - org.apache.sshd.server.command;version="[2.12.0,2.13.0)", - org.apache.sshd.server.session;version="[2.12.0,2.13.0)", - org.apache.sshd.server.shell;version="[2.12.0,2.13.0)", - org.apache.sshd.server.subsystem;version="[2.12.0,2.13.0)", - org.apache.sshd.sftp;version="[2.12.0,2.13.0)", - org.apache.sshd.sftp.server;version="[2.12.0,2.13.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", +Import-Package: org.apache.sshd.common;version="[2.15.0,2.16.0)", + org.apache.sshd.common.config.keys;version="[2.15.0,2.16.0)", + org.apache.sshd.common.file.virtualfs;version="[2.15.0,2.16.0)", + org.apache.sshd.common.helpers;version="[2.15.0,2.16.0)", + org.apache.sshd.common.io;version="[2.15.0,2.16.0)", + org.apache.sshd.common.kex;version="[2.15.0,2.16.0)", + org.apache.sshd.common.keyprovider;version="[2.15.0,2.16.0)", + org.apache.sshd.common.session;version="[2.15.0,2.16.0)", + org.apache.sshd.common.signature;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.buffer;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.logging;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.security;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.threads;version="[2.15.0,2.16.0)", + org.apache.sshd.core;version="[2.15.0,2.16.0)", + org.apache.sshd.server;version="[2.15.0,2.16.0)", + org.apache.sshd.server.auth;version="[2.15.0,2.16.0)", + org.apache.sshd.server.auth.gss;version="[2.15.0,2.16.0)", + org.apache.sshd.server.auth.keyboard;version="[2.15.0,2.16.0)", + org.apache.sshd.server.auth.password;version="[2.15.0,2.16.0)", + org.apache.sshd.server.command;version="[2.15.0,2.16.0)", + org.apache.sshd.server.session;version="[2.15.0,2.16.0)", + org.apache.sshd.server.shell;version="[2.15.0,2.16.0)", + org.apache.sshd.server.subsystem;version="[2.15.0,2.16.0)", + org.apache.sshd.sftp;version="[2.15.0,2.16.0)", + org.apache.sshd.sftp.server;version="[2.15.0,2.16.0)", + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", org.slf4j;version="[1.7.0,3.0.0)" -Export-Package: org.eclipse.jgit.junit.ssh;version="7.0.0" +Export-Package: org.eclipse.jgit.junit.ssh;version="7.3.0"
diff --git a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF index a7ca633..27d1737 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.junit.ssh - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.ssh.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml index 2a885f2..cbdfa31 100644 --- a/org.eclipse.jgit.junit.ssh/pom.xml +++ b/org.eclipse.jgit.junit.ssh/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.junit.ssh</artifactId>
diff --git a/org.eclipse.jgit.junit/.settings/.api_filters b/org.eclipse.jgit.junit/.settings/.api_filters new file mode 100644 index 0000000..2781530 --- /dev/null +++ b/org.eclipse.jgit.junit/.settings/.api_filters
@@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<component id="org.eclipse.jgit.junit" version="2"> + <resource path="src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java" type="org.eclipse.jgit.junit.LocalDiskRepositoryTestCase"> + <filter id="336658481"> + <message_arguments> + <message_argument value="org.eclipse.jgit.junit.LocalDiskRepositoryTestCase"/> + <message_argument value="testRoot"/> + </message_arguments> + </filter> + </resource> +</component>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF index af1cbf2..5f0546e 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -3,36 +3,36 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.dircache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.merge;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="7.0.0", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.io;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.time;version="[7.0.0,7.1.0)", +Import-Package: org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.dircache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.merge;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="7.3.0", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.io;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.time;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.rules;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)", org.junit.runners;version="[4.13,5.0.0)", org.junit.runners.model;version="[4.13,5.0.0)", org.slf4j;version="[1.7.0,3.0.0)" -Export-Package: org.eclipse.jgit.junit;version="7.0.0"; +Export-Package: org.eclipse.jgit.junit;version="7.3.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -45,4 +45,4 @@ org.junit.runners.model, org.junit.runner, org.eclipse.jgit.util.time", - org.eclipse.jgit.junit.time;version="7.0.0";uses:="org.eclipse.jgit.util.time" + org.eclipse.jgit.junit.time;version="7.3.0";uses:="org.eclipse.jgit.util.time"
diff --git a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF index 149ad00..4e0108a 100644 --- a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.junit - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index c33cb29..dbb8b06 100644 --- a/org.eclipse.jgit.junit/pom.xml +++ b/org.eclipse.jgit.junit/pom.xml
@@ -19,7 +19,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java new file mode 100644 index 0000000..eb23bec --- /dev/null +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java
@@ -0,0 +1,243 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * 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.junit; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toUnmodifiableList; + +import java.io.IOException; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.file.PackIndex.EntriesIterator; +import org.eclipse.jgit.internal.storage.file.PackReverseIndex; +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; + +/** + * Create indexes with predefined data + * + * @since 7.2 + */ +public class FakeIndexFactory { + + /** + * An object for the fake index + * + * @param name + * a sha1 + * @param offset + * the (fake) position of the object in the pack + */ + public record IndexObject(String name, long offset) { + /** + * Name (sha1) as an objectId + * + * @return name (a sha1) as an objectId. + */ + public ObjectId getObjectId() { + return ObjectId.fromString(name); + } + } + + /** + * Return an index populated with these objects + * + * @param objs + * objects to be indexed + * @return a PackIndex implementation + */ + public static PackIndex indexOf(List<IndexObject> objs) { + return new FakePackIndex(objs); + } + + /** + * Return a reverse pack index with these objects + * + * @param objs + * objects to be indexed + * @return a PackReverseIndex implementation + */ + public static PackReverseIndex reverseIndexOf(List<IndexObject> objs) { + return new FakeReverseIndex(objs); + } + + private FakeIndexFactory() { + } + + private static class FakePackIndex implements PackIndex { + private static final Comparator<IndexObject> SHA1_COMPARATOR = (o1, + o2) -> String.CASE_INSENSITIVE_ORDER.compare(o1.name(), + o2.name()); + + private final Map<String, IndexObject> idx; + + private final List<IndexObject> sha1Ordered; + + private final long offset64count; + + FakePackIndex(List<IndexObject> objs) { + sha1Ordered = objs.stream().sorted(SHA1_COMPARATOR) + .collect(toUnmodifiableList()); + idx = objs.stream().collect(toMap(IndexObject::name, identity())); + offset64count = objs.stream() + .filter(o -> o.offset > Integer.MAX_VALUE).count(); + } + + @Override + public Iterator<MutableEntry> iterator() { + return new FakeEntriesIterator(sha1Ordered); + } + + @Override + public long getObjectCount() { + return sha1Ordered.size(); + } + + @Override + public long getOffset64Count() { + return offset64count; + } + + @Override + public ObjectId getObjectId(long nthPosition) { + return ObjectId + .fromString(sha1Ordered.get((int) nthPosition).name()); + } + + @Override + public long getOffset(long nthPosition) { + return sha1Ordered.get((int) nthPosition).offset(); + } + + @Override + public long findOffset(AnyObjectId objId) { + IndexObject o = idx.get(objId.name()); + if (o == null) { + return -1; + } + return o.offset(); + } + + @Override + public int findPosition(AnyObjectId objId) { + IndexObject o = idx.get(objId.name()); + if (o == null) { + return -1; + } + return sha1Ordered.indexOf(o); + } + + @Override + public long findCRC32(AnyObjectId objId) throws MissingObjectException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasCRC32Support() { + return false; + } + + @Override + public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, + int matchLimit) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] getChecksum() { + return new byte[0]; + } + } + + private static class FakeReverseIndex implements PackReverseIndex { + private static final Comparator<IndexObject> OFFSET_COMPARATOR = Comparator + .comparingLong(IndexObject::offset); + + private final List<IndexObject> byOffset; + + private final Map<Long, IndexObject> ridx; + + FakeReverseIndex(List<IndexObject> objs) { + byOffset = objs.stream().sorted(OFFSET_COMPARATOR) + .collect(toUnmodifiableList()); + ridx = byOffset.stream() + .collect(toMap(IndexObject::offset, identity())); + } + + @Override + public void verifyPackChecksum(String packFilePath) { + // Do nothing + } + + @Override + public ObjectId findObject(long offset) { + IndexObject indexObject = ridx.get(offset); + if (indexObject == null) { + return null; + } + return ObjectId.fromString(indexObject.name()); + } + + @Override + public long findNextOffset(long offset, long maxOffset) + throws CorruptObjectException { + IndexObject o = ridx.get(offset); + if (o == null) { + throw new CorruptObjectException("Invalid offset"); //$NON-NLS-1$ + } + int pos = byOffset.indexOf(o); + if (pos == byOffset.size() - 1) { + return maxOffset; + } + return byOffset.get(pos + 1).offset(); + } + + @Override + public int findPosition(long offset) { + IndexObject indexObject = ridx.get(offset); + return byOffset.indexOf(indexObject); + } + + @Override + public ObjectId findObjectByPosition(int nthPosition) { + return byOffset.get(nthPosition).getObjectId(); + } + } + + private static class FakeEntriesIterator extends EntriesIterator { + + private static final byte[] buffer = new byte[Constants.OBJECT_ID_LENGTH]; + + private final Iterator<IndexObject> it; + + FakeEntriesIterator(List<IndexObject> objs) { + super(objs.size()); + it = objs.iterator(); + } + + @Override + protected void readNext() { + IndexObject next = it.next(); + next.getObjectId().copyRawTo(buffer, 0); + setIdBuffer(buffer, 0); + setOffset(next.offset()); + } + } +}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java index 407290a..0d20f64 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -20,19 +20,19 @@ import java.io.IOException; import java.io.PrintStream; import java.time.Instant; +import java.time.ZoneId; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.internal.storage.file.FileRepository; -import org.eclipse.jgit.internal.util.ShutdownHook; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -47,6 +47,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; +import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; /** @@ -84,6 +85,16 @@ public abstract class LocalDiskRepositoryTestCase { protected MockSystemReader mockSystemReader; private final Set<Repository> toClose = new HashSet<>(); + + /** + * Temporary test root directory for files created by tests. + * @since 7.2 + */ + @Rule + public TemporaryFolder testRoot = new TemporaryFolder(); + + Random rand = new Random(); + private File tmp; private File homeDir; @@ -114,11 +125,8 @@ private String getTestName() { */ @Before public void setUp() throws Exception { - tmp = File.createTempFile("jgit_" + getTestName() + '_', "_tmp"); - Cleanup.deleteOnShutdown(tmp); - if (!tmp.delete() || !tmp.mkdir()) { - throw new IOException("Cannot create " + tmp); - } + tmp = testRoot.newFolder(getTestName() + rand.nextInt()); + mockSystemReader = new MockSystemReader(); SystemReader.setInstance(mockSystemReader); @@ -219,12 +227,6 @@ public void tearDown() throws Exception { System.gc(); } FS.DETECTED.setUserHome(homeDir); - if (tmp != null) { - recursiveDelete(tmp, false, true); - } - if (tmp != null && !tmp.exists()) { - Cleanup.removed(tmp); - } SystemReader.setInstance(null); } @@ -233,8 +235,8 @@ public void tearDown() throws Exception { */ protected void tick() { mockSystemReader.tick(5 * 60); - final long now = mockSystemReader.getCurrentTime(); - final int tz = mockSystemReader.getTimezone(now); + Instant now = mockSystemReader.now(); + ZoneId tz = mockSystemReader.getTimeZoneId(); author = new PersonIdent(author, now, tz); committer = new PersonIdent(committer, now, tz); @@ -623,41 +625,4 @@ protected String read(File f) throws IOException { private static HashMap<String, String> cloneEnv() { return new HashMap<>(System.getenv()); } - - private static final class Cleanup { - private static final Cleanup INSTANCE = new Cleanup(); - - static { - ShutdownHook.INSTANCE.register(() -> INSTANCE.onShutdown()); - } - - private final Set<File> toDelete = ConcurrentHashMap.newKeySet(); - - private Cleanup() { - // empty - } - - static void deleteOnShutdown(File tmp) { - INSTANCE.toDelete.add(tmp); - } - - static void removed(File tmp) { - INSTANCE.toDelete.remove(tmp); - } - - private void onShutdown() { - // On windows accidentally open files or memory - // mapped regions may prevent files from being deleted. - // Suggesting a GC increases the likelihood that our - // test repositories actually get removed after the - // tests, even in the case of failure. - System.gc(); - synchronized (this) { - boolean silent = false; - boolean failOnError = false; - for (File tmp : toDelete) - recursiveDelete(tmp, silent, failOnError); - } - } - } }
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index 419fdb1..38f0d0b 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
@@ -18,6 +18,8 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.Duration; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -242,6 +244,11 @@ public TimeZone getTimeZone() { } @Override + public ZoneId getTimeZoneId() { + return ZoneOffset.ofHoursMinutes(-3, -30); + } + + @Override public Locale getLocale() { return Locale.US; }
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java index c8c56b2..2a482df 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java
@@ -44,7 +44,7 @@ private static Class<?> loadNewClass(Class<?> klass) try { String pathSeparator = System.getProperty("path.separator"); String[] classPathEntries = System.getProperty("java.class.path") - .split(pathSeparator); + .split(pathSeparator, -1); URL[] urls = new URL[classPathEntries.length]; for (int i = 0; i < classPathEntries.length; i++) { urls[i] = Paths.get(classPathEntries[i]).toUri().toURL();
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index a2e0a57..2d00a85 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -21,6 +21,7 @@ import java.io.OutputStream; import java.security.MessageDigest; import java.time.Instant; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -30,6 +31,7 @@ import java.util.Set; import java.util.TimeZone; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; @@ -157,8 +159,8 @@ public TestRepository(R db, RevWalk rw, MockSystemReader reader) this.pool = rw; this.inserter = db.newObjectInserter(); this.mockSystemReader = reader; - long now = mockSystemReader.getCurrentTime(); - int tz = mockSystemReader.getTimezone(now); + Instant now = mockSystemReader.now(); + ZoneId tz = mockSystemReader.getTimeZoneAt(now); defaultAuthor = new PersonIdent(AUTHOR, AUTHOR_EMAIL, now, tz); defaultCommitter = new PersonIdent(COMMITTER, COMMITTER_EMAIL, now, tz); } @@ -197,7 +199,9 @@ public Git git() { * * @return current date. * @since 4.2 + * @deprecated Use {@link #getInstant()} instead. */ + @Deprecated(since = "7.2") public Date getDate() { return new Date(mockSystemReader.getCurrentTime()); } @@ -209,18 +213,31 @@ public Date getDate() { * @since 6.8 */ public Instant getInstant() { - return Instant.ofEpochMilli(mockSystemReader.getCurrentTime()); + return mockSystemReader.now(); } /** * Get timezone * * @return timezone used for default identities. + * @deprecated Use {@link #getTimeZoneId()} instead. */ + @Deprecated(since = "7.2") public TimeZone getTimeZone() { return mockSystemReader.getTimeZone(); } + + /** + * Get timezone + * + * @return timezone used for default identities. + * @since 7.2 + */ + public ZoneId getTimeZoneId() { + return mockSystemReader.getTimeZoneId(); + } + /** * Adjust the current time that will used by the next commit. * @@ -232,14 +249,14 @@ public void tick(int secDelta) { } /** - * Set the author and committer using {@link #getDate()}. + * Set the author and committer using {@link #getInstant()}. * * @param c * the commit builder to store. */ public void setAuthorAndCommitter(org.eclipse.jgit.lib.CommitBuilder c) { - c.setAuthor(new PersonIdent(defaultAuthor, getDate())); - c.setCommitter(new PersonIdent(defaultCommitter, getDate())); + c.setAuthor(new PersonIdent(defaultAuthor, getInstant())); + c.setCommitter(new PersonIdent(defaultCommitter, getInstant())); } /** @@ -487,8 +504,8 @@ public ObjectId unparsedCommit(final int secDelta, final RevTree tree, c = new org.eclipse.jgit.lib.CommitBuilder(); c.setTreeId(tree); c.setParentIds(parents); - c.setAuthor(new PersonIdent(defaultAuthor, getDate())); - c.setCommitter(new PersonIdent(defaultCommitter, getDate())); + c.setAuthor(new PersonIdent(defaultAuthor, getInstant())); + c.setCommitter(new PersonIdent(defaultCommitter, getInstant())); c.setMessage(""); ObjectId id; try (ObjectInserter ins = inserter) { @@ -528,7 +545,7 @@ public RevTag tag(String name, RevObject dst) throws Exception { final TagBuilder t = new TagBuilder(); t.setObjectId(dst); t.setTag(name); - t.setTagger(new PersonIdent(defaultCommitter, getDate())); + t.setTagger(new PersonIdent(defaultCommitter, getInstant())); t.setMessage(""); ObjectId id; try (ObjectInserter ins = inserter) { @@ -797,7 +814,7 @@ public RevCommit cherryPick(AnyObjectId id) throws Exception { b.setParentId(head); b.setTreeId(merger.getResultTreeId()); b.setAuthor(commit.getAuthorIdent()); - b.setCommitter(new PersonIdent(defaultCommitter, getDate())); + b.setCommitter(new PersonIdent(defaultCommitter, getInstant())); b.setMessage(commit.getFullMessage()); ObjectId result; try (ObjectInserter ins = inserter) { @@ -1019,7 +1036,8 @@ public void close() { private static void prunePacked(ObjectDirectory odb) throws IOException { for (Pack p : odb.getPacks()) { for (MutableEntry e : p) - FileUtils.delete(odb.fileFor(e.toObjectId())); + FileUtils.delete(odb.fileFor(e.toObjectId()), + FileUtils.SKIP_MISSING); } } @@ -1144,15 +1162,18 @@ public class CommitBuilder { } /** - * set parent commit + * Set parent commit * * @param p - * parent commit + * parent commit, can be {@code null} * @return this commit builder * @throws Exception * if an error occurred */ - public CommitBuilder parent(RevCommit p) throws Exception { + public CommitBuilder parent(@Nullable RevCommit p) throws Exception { + if (p == null) { + return this; + } if (parents.isEmpty()) { DirCacheBuilder b = tree.builder(); parseBody(p); @@ -1403,7 +1424,7 @@ public RevCommit create() throws Exception { c.setAuthor(author); if (committer != null) { if (updateCommitterTime) - committer = new PersonIdent(committer, getDate()); + committer = new PersonIdent(committer, getInstant()); c.setCommitter(committer); }
diff --git a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF index 8e41ee3..8feb8ef 100644 --- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.server.test Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -26,24 +26,24 @@ org.eclipse.jetty.util.component;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.security;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.thread;version="[12.0.0,13.0.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.server;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.server.fs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.test;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.server;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.server.fs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.test;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.hamcrest.core;version="[1.1.0,3.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.rules;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml index 49c1023..176f4af 100644 --- a/org.eclipse.jgit.lfs.server.test/pom.xml +++ b/org.eclipse.jgit.lfs.server.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.server.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF index a59c82e..ed8cfff 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.server Bundle-SymbolicName: org.eclipse.jgit.lfs.server -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.lfs.server;version="7.0.0"; +Export-Package: org.eclipse.jgit.lfs.server;version="7.3.0"; uses:="jakarta.servlet.http, org.eclipse.jgit.lfs.lib", - org.eclipse.jgit.lfs.server.fs;version="7.0.0"; + org.eclipse.jgit.lfs.server.fs;version="7.3.0"; uses:="jakarta.servlet, jakarta.servlet.http, org.eclipse.jgit.lfs.server, org.eclipse.jgit.lfs.lib", - org.eclipse.jgit.lfs.server.internal;version="7.0.0";x-internal:=true, - org.eclipse.jgit.lfs.server.s3;version="7.0.0"; + org.eclipse.jgit.lfs.server.internal;version="7.3.0";x-internal:=true, + org.eclipse.jgit.lfs.server.s3;version="7.3.0"; uses:="org.eclipse.jgit.lfs.server, org.eclipse.jgit.lfs.lib" Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -24,15 +24,15 @@ jakarta.servlet.annotation;version="[6.0.0,7.0.0)", jakarta.servlet.http;version="[6.0.0,7.0.0)", org.apache.http;version="[4.3.0,5.0.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http.apache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http.apache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.slf4j;version="[1.7.0,3.0.0)"
diff --git a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF index 2cf86bc..7e26500 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.lfs.server - Sources Bundle-SymbolicName: org.eclipse.jgit.lfs.server.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml index befaa36..ebb815f 100644 --- a/org.eclipse.jgit.lfs.server/pom.xml +++ b/org.eclipse.jgit.lfs.server/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.server</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF index 96c8953..b8a2ca7 100644 --- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -3,27 +3,28 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.test Bundle-SymbolicName: org.eclipse.jgit.lfs.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.attributes;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", +Import-Package: org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.attributes;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.hamcrest.core;version="[1.1.0,3.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)", org.junit.runners;version="[4.13,5.0.0)" -Export-Package: org.eclipse.jgit.lfs.test;version="7.0.0";x-friends:="org.eclipse.jgit.lfs.server.test" +Export-Package: org.eclipse.jgit.lfs.test;version="7.3.0";x-friends:="org.eclipse.jgit.lfs.server.test"
diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml index 2c109c9..c9591b6 100644 --- a/org.eclipse.jgit.lfs.test/pom.xml +++ b/org.eclipse.jgit.lfs.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.test</artifactId>
diff --git a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java index badcb7d..ee8e893 100644 --- a/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java +++ b/org.eclipse.jgit.lfs.test/tst/org/eclipse/jgit/lfs/internal/LfsConnectionFactoryTest.java
@@ -97,7 +97,8 @@ public void lfsUrlFromRemoteUrlWithoutDotGit() throws Exception { public void lfsUrlFromLocalConfig() throws Exception { addRemoteUrl("https://localhost/repo"); - StoredConfig cfg = ((Repository) db).getConfig(); + @SuppressWarnings("restriction") + StoredConfig cfg = db.getConfig(); cfg.setString(ConfigConstants.CONFIG_SECTION_LFS, null, ConfigConstants.CONFIG_KEY_URL, @@ -111,7 +112,8 @@ public void lfsUrlFromLocalConfig() throws Exception { public void lfsUrlFromOriginConfig() throws Exception { addRemoteUrl("https://localhost/repo"); - StoredConfig cfg = ((Repository) db).getConfig(); + @SuppressWarnings("restriction") + StoredConfig cfg = db.getConfig(); cfg.setString(ConfigConstants.CONFIG_SECTION_LFS, org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF index f4c1e56..5338f8b 100644 --- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF
@@ -3,32 +3,32 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs Bundle-SymbolicName: org.eclipse.jgit.lfs -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.lfs;version="7.0.0", - org.eclipse.jgit.lfs.errors;version="7.0.0", - org.eclipse.jgit.lfs.internal;version="7.0.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server", - org.eclipse.jgit.lfs.lib;version="7.0.0" +Export-Package: org.eclipse.jgit.lfs;version="7.3.0", + org.eclipse.jgit.lfs.errors;version="7.3.0", + org.eclipse.jgit.lfs.internal;version="7.3.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server", + org.eclipse.jgit.lfs.lib;version="7.3.0" Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: com.google.gson;version="[2.8.2,3.0.0)", com.google.gson.stream;version="[2.8.2,3.0.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)";resolution:=optional, - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.attributes;version="[7.0.0,7.1.0)", - org.eclipse.jgit.diff;version="[7.0.0,7.1.0)", - org.eclipse.jgit.dircache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.hooks;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.pack;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.io;version="[7.0.0,7.1.0)" + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)";resolution:=optional, + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.attributes;version="[7.3.0,7.4.0)", + org.eclipse.jgit.diff;version="[7.3.0,7.4.0)", + org.eclipse.jgit.dircache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.hooks;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.pack;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.io;version="[7.3.0,7.4.0)"
diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF index a048aa1..fc12482 100644 --- a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.lfs - Sources Bundle-SymbolicName: org.eclipse.jgit.lfs.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml index 62508e2..d336f16 100644 --- a/org.eclipse.jgit.lfs/pom.xml +++ b/org.eclipse.jgit.lfs/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs</artifactId>
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java index 75d500e..a13a60c 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java
@@ -41,24 +41,6 @@ public abstract class AnyLongObjectId implements Comparable<AnyLongObjectId> { * @param secondObjectId * the second identifier to compare. Must not be null. * @return true if the two identifiers are the same. - * @deprecated use {@link #isEqual(AnyLongObjectId, AnyLongObjectId)} - * instead. - */ - @Deprecated - @SuppressWarnings("AmbiguousMethodReference") - public static boolean equals(final AnyLongObjectId firstObjectId, - final AnyLongObjectId secondObjectId) { - return isEqual(firstObjectId, secondObjectId); - } - - /** - * Compare two object identifier byte sequences for equality. - * - * @param firstObjectId - * the first identifier to compare. Must not be null. - * @param secondObjectId - * the second identifier to compare. Must not be null. - * @return true if the two identifiers are the same. * @since 5.4 */ public static boolean isEqual(final AnyLongObjectId firstObjectId, @@ -263,7 +245,7 @@ public final int hashCode() { */ @SuppressWarnings({ "NonOverridingEquals", "AmbiguousMethodReference" }) public final boolean equals(AnyLongObjectId other) { - return other != null ? equals(this, other) : false; + return other != null ? isEqual(this, other) : false; } @Override
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml index 3dd7b10..adea43b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml index ea66a23..734b634 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml index 23fdd23..f86652f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.gpg.bc" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import plugin="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml index fc1bf49..a756a8d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.gpg.bc.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml index 92262a0..d999c15 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.http.apache" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import plugin="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml index 3344dcb..c2ca95a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml index 6f03419..922622c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.junit" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -24,7 +24,7 @@ <requires> <import plugin="com.jcraft.jsch"/> - <import plugin="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml index 45162c9..71e7373 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml index 8eacae1..53cb4bac 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.lfs" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml index 287a723..31ba89f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml index 179eab8..2d7ee4e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.pgm" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -35,9 +35,9 @@ version="0.0.0"/> <requires> - <import feature="org.eclipse.jgit" version="7.0.0" match="equivalent"/> - <import feature="org.eclipse.jgit.lfs" version="7.0.0" match="equivalent"/> - <import feature="org.eclipse.jgit.ssh.apache" version="7.0.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.3.0" match="equivalent"/> + <import feature="org.eclipse.jgit.lfs" version="7.3.0" match="equivalent"/> + <import feature="org.eclipse.jgit.ssh.apache" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml index cbb8e4f..2c80319 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml index f46e08d..eef699c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
@@ -123,12 +123,6 @@ <bundle id="org.eclipse.jetty.util.ajax.source"> <category name="JGit-dependency-bundles"/> </bundle> - <bundle id="net.i2p.crypto.eddsa"> - <category name="JGit-dependency-bundles"/> - </bundle> - <bundle id="net.i2p.crypto.eddsa.source"> - <category name="JGit-dependency-bundles"/> - </bundle> <bundle id="org.apache.ant"> <category name="JGit-dependency-bundles"/> </bundle> @@ -147,10 +141,13 @@ <bundle id="org.apache.commons.commons-compress.source"> <category name="JGit-dependency-bundles"/> </bundle> - <bundle id="org.apache.commons.logging"> + <bundle id="org.apache.commons.lang3"> <category name="JGit-dependency-bundles"/> </bundle> - <bundle id="org.apache.commons.logging.source"> + <bundle id="org.apache.commons.lang3.source"> + <category name="JGit-dependency-bundles"/> + </bundle> + <bundle id="org.apache.commons.logging"> <category name="JGit-dependency-bundles"/> </bundle> <bundle id="org.apache.httpcomponents.httpclient">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml index 61b5dd6..032072f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml index 4c0068b..139569d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.source" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml index 12ab069..43568f8 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> @@ -30,7 +30,7 @@ <dependency> <groupId>org.eclipse.jgit.feature</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml index 209274f..7f80bbf 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.ssh.apache" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml index 1d82d4a..fb9f73b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml index ff46d9e..5eaa3b7 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/feature.xml
@@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.ssh.jsch" label="%featureName" - version="7.0.0.qualifier" + version="7.3.0.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import plugin="org.eclipse.jgit" version="7.0.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.3.0" match="equivalent"/> </requires> <plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml index c4d4fcf..d5da669 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.jsch.feature/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId>
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 deleted file mode 100644 index 8899b51..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?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="1715125111"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </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 deleted file mode 100644 index b3ff205..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.17" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2020-09/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target deleted file mode 100644 index ee56a72..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.18" sequenceNumber="1715125111"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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-12/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd deleted file mode 100644 index 719476a..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.18" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2020-12/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target deleted file mode 100644 index ad35e58..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.19-staging" sequenceNumber="1715125111"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2021-03/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd deleted file mode 100644 index 9eb4436..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.19-staging" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2021-03/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target deleted file mode 100644 index 4031c04..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.20" sequenceNumber="1715125111"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2021-06/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd deleted file mode 100644 index 264c040..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.20" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2021-06/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target deleted file mode 100644 index 1a119f2..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.21" sequenceNumber="1715125111"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2021-09/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd deleted file mode 100644 index 5c7a112..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.21" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2021-09/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target deleted file mode 100644 index 1f6ee4e..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.22" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2021-12/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd deleted file mode 100644 index ecc776e..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.22" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2021-12/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target deleted file mode 100644 index d0a0420..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.23" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </location> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="https://download.eclipse.org/releases/2022-03/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd deleted file mode 100644 index 16efb40..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.23" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2022-03/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target deleted file mode 100644 index dc9e090..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.24" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </location> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="https://download.eclipse.org/releases/2022-06/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd deleted file mode 100644 index d0f8e8d..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.24" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2022-06/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target deleted file mode 100644 index 53dcb36..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.25" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </location> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="https://download.eclipse.org/releases/2022-09/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.tpd deleted file mode 100644 index be37c10..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.25" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2022-09/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target deleted file mode 100644 index 822c7cf..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.26" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </location> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="https://download.eclipse.org/releases/2022-12/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.tpd deleted file mode 100644 index e269919..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.26" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2022-12/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target deleted file mode 100644 index 9a0cab4..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.27" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2023-03/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.tpd deleted file mode 100644 index b67718a..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.27" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2023-03/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target deleted file mode 100644 index 22aa30e..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.28" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2023-06"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.tpd deleted file mode 100644 index 1a9a22a..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.28" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2023-06" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target deleted file mode 100644 index f7fb7c9..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.29" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2023-09"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.tpd deleted file mode 100644 index 4e34280..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.29" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2023-09" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target deleted file mode 100644 index 733559d..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.30" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2023-12/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.tpd deleted file mode 100644 index dfb4474..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.30" with source configurePhase - -include "orbit/orbit-4.30.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/staging/2023-12/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target deleted file mode 100644 index 78ef168..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target +++ /dev/null
@@ -1,284 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.31" sequenceNumber="1715125110"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="net.i2p.crypto.eddsa" version="0.3.0"/> - <unit id="net.i2p.crypto.eddsa.source" version="0.3.0"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.3.0"/> - <unit id="org.objenesis.source" version="3.3.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12"/> - </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/2024-03/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.9</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.12.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.10.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.14.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.0.9</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.0.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.10.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.14.12</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.77</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.25.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.33</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.26.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.15.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.tpd deleted file mode 100644 index 58491c8..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.31" with source configurePhase - -include "orbit/orbit-4.31.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/staging/2024-03/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target new file mode 100644 index 0000000..60baf0b --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target
@@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?pde?> +<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> +<target name="jgit-4.32" sequenceNumber="1740521280"> + <locations> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> + <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> + <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> + <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> + <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.junit" version="4.13.2.v20230809-1000"/> + <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> + <unit id="org.objenesis" version="3.4.0"/> + <unit id="org.objenesis.source" version="3.4.0"/> + <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> + <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> + <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-06"/> + </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/2024-06/"/> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> + <dependencies> + <dependency> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + <version>1.10</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> + <dependencies> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-osgi</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-sftp</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> + <dependencies> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>5.15.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> + <dependencies> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-servlet</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-session</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>6.1.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> + <dependencies> + <dependency> + <groupId>com.googlecode.javaewah</groupId> + <artifactId>JavaEWAH</artifactId> + <version>1.2.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> + <dependencies> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>2.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> + <dependencies> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.12.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> + <dependencies> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> + <dependencies> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpg-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcutil-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> + <dependencies> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.27.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> + <dependencies> + <dependency> + <groupId>args4j</groupId> + <artifactId>args4j</artifactId> + <version>2.37</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> + <dependencies> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.27.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.17.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.3.5</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + </locations> +</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.tpd new file mode 100644 index 0000000..b8574c7 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.tpd
@@ -0,0 +1,8 @@ +target "jgit-4.32" with source configurePhase + +include "orbit/orbit-4.32.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/staging/2024-06/" { + org.eclipse.osgi lazy +}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target new file mode 100644 index 0000000..1558ad6 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target
@@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?pde?> +<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> +<target name="jgit-4.33" sequenceNumber="1740521283"> + <locations> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> + <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> + <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> + <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> + <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.junit" version="4.13.2.v20230809-1000"/> + <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> + <unit id="org.objenesis" version="3.4.0"/> + <unit id="org.objenesis.source" version="3.4.0"/> + <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> + <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> + <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-09"/> + </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/2024-09/"/> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> + <dependencies> + <dependency> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + <version>1.10</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> + <dependencies> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-osgi</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-sftp</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> + <dependencies> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>5.15.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> + <dependencies> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-servlet</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-session</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>6.1.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> + <dependencies> + <dependency> + <groupId>com.googlecode.javaewah</groupId> + <artifactId>JavaEWAH</artifactId> + <version>1.2.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> + <dependencies> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>2.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> + <dependencies> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.12.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> + <dependencies> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> + <dependencies> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpg-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcutil-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> + <dependencies> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.27.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> + <dependencies> + <dependency> + <groupId>args4j</groupId> + <artifactId>args4j</artifactId> + <version>2.37</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> + <dependencies> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.27.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.17.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.3.5</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + </locations> +</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.tpd new file mode 100644 index 0000000..74c6878 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.tpd
@@ -0,0 +1,8 @@ +target "jgit-4.33" with source configurePhase + +include "orbit/orbit-4.33.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/releases/2024-09/" { + org.eclipse.osgi lazy +}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target new file mode 100644 index 0000000..bc35d2c --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
@@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?pde?> +<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> +<target name="jgit-4.34" sequenceNumber="1740521284"> + <locations> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> + <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> + <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> + <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.junit" version="4.13.2.v20240929-1000"/> + <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objenesis" version="3.4.0"/> + <unit id="org.objenesis.source" version="3.4.0"/> + <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> + <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> + <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-12"/> + </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/2024-12/"/> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> + <dependencies> + <dependency> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + <version>1.10</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> + <dependencies> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-osgi</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-sftp</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> + <dependencies> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>5.15.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> + <dependencies> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-servlet</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-session</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>6.1.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> + <dependencies> + <dependency> + <groupId>com.googlecode.javaewah</groupId> + <artifactId>JavaEWAH</artifactId> + <version>1.2.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> + <dependencies> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>2.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> + <dependencies> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.12.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> + <dependencies> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> + <dependencies> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpg-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcutil-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> + <dependencies> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.27.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> + <dependencies> + <dependency> + <groupId>args4j</groupId> + <artifactId>args4j</artifactId> + <version>2.37</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> + <dependencies> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.27.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.17.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.3.5</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + </locations> +</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.tpd new file mode 100644 index 0000000..4c38371 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.tpd
@@ -0,0 +1,8 @@ +target "jgit-4.34" with source configurePhase + +include "orbit/orbit-4.34.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/staging/2024-12/" { + org.eclipse.osgi lazy +}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target new file mode 100644 index 0000000..15cabc3 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
@@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?pde?> +<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> +<target name="jgit-4.35" sequenceNumber="1740521286"> + <locations> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> + <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> + <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> + <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> + <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.junit" version="4.13.2.v20240929-1000"/> + <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objenesis" version="3.4.0"/> + <unit id="org.objenesis.source" version="3.4.0"/> + <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> + <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> + <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2025-03"/> + </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/2025-03/"/> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> + <dependencies> + <dependency> + <groupId>org.tukaani</groupId> + <artifactId>xz</artifactId> + <version>1.10</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.36</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> + <dependencies> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-osgi</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-sftp</artifactId> + <version>2.15.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> + <dependencies> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>5.15.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> + <dependencies> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <version>5.16.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.ee10</groupId> + <artifactId>jetty-ee10-servlet</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-session</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>12.0.16</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>6.1.0</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> + <dependencies> + <dependency> + <groupId>com.googlecode.javaewah</groupId> + <artifactId>JavaEWAH</artifactId> + <version>1.2.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> + <dependencies> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>2.2</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> + <dependencies> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.12.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> + <dependencies> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>1.17.1</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> + <dependencies> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpg-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcutil-jdk18on</artifactId> + <version>1.80</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> + <dependencies> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.27.3</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> + <dependencies> + <dependency> + <groupId>args4j</groupId> + <artifactId>args4j</artifactId> + <version>2.37</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> + <dependencies> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-compress</artifactId> + <version>1.27.1</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.17.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.18.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.3.5</version> + <type>jar</type> + </dependency> + </dependencies> + </location> + </locations> +</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.tpd new file mode 100644 index 0000000..3c0646e --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.tpd
@@ -0,0 +1,8 @@ +target "jgit-4.35" with source configurePhase + +include "orbit/orbit-4.35.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/staging/2025-03/" { + org.eclipse.osgi lazy +}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd index a25f9c9..b292cf5 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
@@ -10,22 +10,27 @@ dependency { groupId = "commons-codec" artifactId = "commons-codec" - version = "1.16.0" + version = "1.18.0" } dependency { groupId = "org.apache.commons" artifactId = "commons-compress" - version = "1.26.0" + version = "1.27.1" + } + dependency { + groupId = "org.apache.commons" + artifactId = "commons-lang3" + version = "3.17.0" } dependency { groupId = "commons-io" artifactId = "commons-io" - version = "2.15.1" + version = "2.18.0" } dependency { groupId = "commons-logging" artifactId = "commons-logging" - version = "1.2" + version = "1.3.5" } } @@ -38,7 +43,7 @@ dependency { groupId = "args4j" artifactId = "args4j" - version = "2.33" + version = "2.37" } } @@ -51,7 +56,7 @@ dependency { groupId = "org.assertj" artifactId = "assertj-core" - version = "3.25.3" + version = "3.27.3" } } @@ -64,22 +69,22 @@ dependency { groupId = "org.bouncycastle" artifactId = "bcpg-jdk18on" - version = "1.77" + version = "1.80" } dependency { groupId = "org.bouncycastle" artifactId = "bcprov-jdk18on" - version = "1.77" + version = "1.80" } dependency { groupId = "org.bouncycastle" artifactId = "bcpkix-jdk18on" - version = "1.77" + version = "1.80" } dependency { groupId = "org.bouncycastle" artifactId = "bcutil-jdk18on" - version = "1.77" + version = "1.80" } } @@ -92,12 +97,12 @@ dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy" - version = "1.14.12" + version = "1.17.1" } dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy-agent" - version = "1.14.12" + version = "1.17.1" } } @@ -110,7 +115,7 @@ dependency { groupId = "com.google.code.gson" artifactId = "gson" - version = "2.10.1" + version = "2.12.1" } } @@ -149,47 +154,47 @@ dependency { groupId = "org.eclipse.jetty.ee10" artifactId = "jetty-ee10-servlet" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-http" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-io" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-security" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-server" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-session" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util-ajax" - version = "12.0.9" + version = "12.0.16" } dependency { groupId = "jakarta.servlet" artifactId = "jakarta.servlet-api" - version = "6.0.0" + version = "6.1.0" } } @@ -202,12 +207,12 @@ dependency { groupId = "net.java.dev.jna" artifactId = "jna" - version = "5.14.0" + version = "5.16.0" } dependency { groupId = "net.java.dev.jna" artifactId = "jna-platform" - version = "5.14.0" + version = "5.16.0" } } @@ -220,7 +225,7 @@ dependency { groupId = "org.mockito" artifactId = "mockito-core" - version = "5.10.0" + version = "5.15.2" } } @@ -233,12 +238,12 @@ dependency { groupId = "org.apache.sshd" artifactId = "sshd-osgi" - version = "2.12.0" + version = "2.15.0" } dependency { groupId = "org.apache.sshd" artifactId = "sshd-sftp" - version = "2.12.0" + version = "2.15.0" } } @@ -269,6 +274,6 @@ dependency { groupId = "org.tukaani" artifactId = "xz" - version = "1.9" + version = "1.10" } } \ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20200831200620-2020-09.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20200831200620-2020-09.tpd deleted file mode 100644 index 22e2b01..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20200831200620-2020-09.tpd +++ /dev/null
@@ -1,66 +0,0 @@ -target "R20200831200620-2020-09" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -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] - 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.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.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.2.v20121108-1250,1.7.2.v20121108-1250] - org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250] - org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200] - org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200] - 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/orbit/R20201130205003-2020-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20201130205003-2020-12.tpd deleted file mode 100644 index 08a0846..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20201130205003-2020-12.tpd +++ /dev/null
@@ -1,66 +0,0 @@ -target "R20201130205003-2020-12" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20201130205003/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/orbit/R20210223232630-2021-03.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210223232630-2021-03.tpd deleted file mode 100644 index 605a43b..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210223232630-2021-03.tpd +++ /dev/null
@@ -1,66 +0,0 @@ -target "R20210223232630-2021-03" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20210223232630/repository" { - com.google.gson [2.8.6.v20201231-1626,2.8.6.v20201231-1626] - com.google.gson.source [2.8.6.v20201231-1626,2.8.6.v20201231-1626] - 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.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - 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.6.0.v20210201-2003,2.6.0.v20210201-2003] - org.apache.sshd.osgi.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003] - org.apache.sshd.sftp [2.6.0.v20210201-2003,2.6.0.v20210201-2003] - org.apache.sshd.sftp.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003] - 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/orbit/R20210602031627-2021-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210602031627-2021-06.tpd deleted file mode 100644 index 83b5bb3..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210602031627-2021-06.tpd +++ /dev/null
@@ -1,66 +0,0 @@ -target "R20210602031627-2021-06" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20210602031627/repository" { - com.google.gson [2.8.6.v20201231-1626,2.8.6.v20201231-1626] - com.google.gson.source [2.8.6.v20201231-1626,2.8.6.v20201231-1626] - 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.10.v20210426-1926,1.10.10.v20210426-1926] - org.apache.ant.source [1.10.10.v20210426-1926,1.10.10.v20210426-1926] - 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.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - 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.6.0.v20210201-2003,2.6.0.v20210201-2003] - org.apache.sshd.osgi.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003] - org.apache.sshd.sftp [2.6.0.v20210201-2003,2.6.0.v20210201-2003] - org.apache.sshd.sftp.source [2.6.0.v20210201-2003,2.6.0.v20210201-2003] - 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/orbit/R20210825222808-2021-09.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210825222808-2021-09.tpd deleted file mode 100644 index 99f3520..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210825222808-2021-09.tpd +++ /dev/null
@@ -1,73 +0,0 @@ -target "R20210825222808-2021-09" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20210825222808/repository" { - com.google.gson [2.8.7.v20210624-1215,2.8.7.v20210624-1215] - com.google.gson.source [2.8.7.v20210624-1215,2.8.7.v20210624-1215] - com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] - com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] - com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - javaewah [1.1.12.v20210622-2206,1.1.12.v20210622-2206] - javaewah.source [1.1.12.v20210622-2206,1.1.12.v20210622-2206] - 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.11.v20210720-1445,1.10.11.v20210720-1445] - org.apache.ant.source [1.10.11.v20210720-1445,1.10.11.v20210720-1445] - 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.20.0.v20210713-1928,1.20.0.v20210713-1928] - org.apache.commons.compress.source [1.20.0.v20210713-1928,1.20.0.v20210713-1928] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - 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.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.osgi.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.sftp [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.sftp.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpg.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpkix [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpkix.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcprov [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcprov.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcutil [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcutil.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.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.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20211122181901-2021-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20211122181901-2021-12.tpd deleted file mode 100644 index cd1d1c0..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20211122181901-2021-12.tpd +++ /dev/null
@@ -1,71 +0,0 @@ -target "R20211122181901-2021-12" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20211122181901/repository" { - com.google.gson [2.8.8.v20211029-0838,2.8.8.v20211029-0838] - com.google.gson.source [2.8.8.v20211029-0838,2.8.8.v20211029-0838] - com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] - com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] - com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.i2p.crypto.eddsa [0.3.0.v20210923-1401,0.3.0.v20210923-1401] - net.i2p.crypto.eddsa.source [0.3.0.v20210923-1401,0.3.0.v20210923-1401] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - 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.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.osgi.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.sftp [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.sftp.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpg.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpkix [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpkix.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcprov [1.69.0.v20210923-1401,1.69.0.v20210923-1401] - org.bouncycastle.bcprov.source [1.69.0.v20210923-1401,1.69.0.v20210923-1401] - org.bouncycastle.bcutil [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcutil.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.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.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20211213173813-2021-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20211213173813-2021-12.tpd deleted file mode 100644 index 0c7c846..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20211213173813-2021-12.tpd +++ /dev/null
@@ -1,69 +0,0 @@ -target "R20211213173813-2021-12" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20211213173813/repository" { - com.google.gson [2.8.8.v20211029-0838,2.8.8.v20211029-0838] - com.google.gson.source [2.8.8.v20211029-0838,2.8.8.v20211029-0838] - com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] - com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] - com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.i2p.crypto.eddsa [0.3.0.v20210923-1401,0.3.0.v20210923-1401] - net.i2p.crypto.eddsa.source [0.3.0.v20210923-1401,0.3.0.v20210923-1401] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225] - org.apache.sshd.osgi [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.osgi.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.sftp [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.apache.sshd.sftp.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpg.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpkix [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcpkix.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcprov [1.69.0.v20210923-1401,1.69.0.v20210923-1401] - org.bouncycastle.bcprov.source [1.69.0.v20210923-1401,1.69.0.v20210923-1401] - org.bouncycastle.bcutil [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.bouncycastle.bcutil.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220302172233-2022-03.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220302172233-2022-03.tpd deleted file mode 100644 index fafc689..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220302172233-2022-03.tpd +++ /dev/null
@@ -1,69 +0,0 @@ -target "R20220302172233" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20220302172233/repository" { - com.google.gson [2.8.9.v20220111-1409,2.8.9.v20220111-1409] - com.google.gson.source [2.8.9.v20220111-1409,2.8.9.v20220111-1409] - com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] - com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] - com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.i2p.crypto.eddsa [0.3.0.v20210923-1401,0.3.0.v20210923-1401] - net.i2p.crypto.eddsa.source [0.3.0.v20210923-1401,0.3.0.v20210923-1401] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.httpcomponents.httpcore.source [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.sshd.osgi [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.osgi.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.sftp [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.sftp.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcpg.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcpkix [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcpkix.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcprov [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcprov.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcutil [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcutil.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd deleted file mode 100644 index 3c74497..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220531185310-2022-06.tpd +++ /dev/null
@@ -1,69 +0,0 @@ -target "R20220531185310-2022-06" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20220531185310/repository" { - com.google.gson [2.8.9.v20220111-1409,2.8.9.v20220111-1409] - com.google.gson.source [2.8.9.v20220111-1409,2.8.9.v20220111-1409] - com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jzlib [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.i2p.crypto.eddsa [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.httpcomponents.httpcore.source [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.sshd.osgi [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.osgi.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.sftp [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.sftp.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.70.0.v20220507-1208,1.70.0.v20220507-1208] - org.bouncycastle.bcpg.source [1.70.0.v20220507-1208,1.70.0.v20220507-1208] - org.bouncycastle.bcpkix [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcpkix.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcprov [1.70.0.v20220507-1208,1.70.0.v20220507-1208] - org.bouncycastle.bcprov.source [1.70.0.v20220507-1208,1.70.0.v20220507-1208] - org.bouncycastle.bcutil [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.bouncycastle.bcutil.source [1.70.0.v20220105-1522,1.70.0.v20220105-1522] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220830213456-2022-09.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220830213456-2022-09.tpd deleted file mode 100644 index 8db1018..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20220830213456-2022-09.tpd +++ /dev/null
@@ -1,69 +0,0 @@ -target "R20220830213456-2022-09" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20220830213456/repository" { - com.google.gson [2.8.9.v20220111-1409,2.8.9.v20220111-1409] - com.google.gson.source [2.8.9.v20220111-1409,2.8.9.v20220111-1409] - com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] - com.jcraft.jzlib [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.sun.jna [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.source [5.8.0.v20210503-0343,5.8.0.v20210503-0343] - com.sun.jna.platform [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - com.sun.jna.platform.source [5.8.0.v20210406-1004,5.8.0.v20210406-1004] - javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534] - net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410] - net.i2p.crypto.eddsa [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422] - org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225] - org.apache.httpcomponents.httpcore [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.httpcomponents.httpcore.source [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.sshd.osgi [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.osgi.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.sftp [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.apache.sshd.sftp.source [2.8.0.v20211227-1750,2.8.0.v20211227-1750] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcpg.source [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcpkix [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcpkix.source [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcprov [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcprov.source [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcutil [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.bouncycastle.bcutil.source [1.71.0.v20220723-1943,1.71.0.v20220723-1943] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642] - org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519] - org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.slf4j.binding.simple.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150] - org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20221123021534-2022-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20221123021534-2022-12.tpd deleted file mode 100644 index 378b848..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20221123021534-2022-12.tpd +++ /dev/null
@@ -1,69 +0,0 @@ -target "S20230101190934" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20221123021534/repository" { - com.google.gson [2.9.1.v20220915-1632,2.9.1.v20220915-1632] - com.google.gson.source [2.9.1.v20220915-1632,2.9.1.v20220915-1632] - com.jcraft.jsch [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jsch.source [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jzlib [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.sun.jna [5.12.1.v20221103-2317,5.12.1.v20221103-2317] - com.sun.jna.source [5.12.1.v20221103-2317,5.12.1.v20221103-2317] - com.sun.jna.platform [5.12.1.v20221103-2317,5.12.1.v20221103-2317] - com.sun.jna.platform.source [5.12.1.v20221103-2317,5.12.1.v20221103-2317] - javaewah [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - javaewah.source [1.1.13.v20211029-0839,1.1.13.v20211029-0839] - net.bytebuddy.byte-buddy [1.12.18.v20221114-2102,1.12.18.v20221114-2102] - net.bytebuddy.byte-buddy.source [1.12.18.v20221114-2102,1.12.18.v20221114-2102] - net.bytebuddy.byte-buddy-agent [1.12.18.v20221114-2102,1.12.18.v20221114-2102] - net.bytebuddy.byte-buddy-agent.source [1.12.18.v20221114-2102,1.12.18.v20221114-2102] - net.i2p.crypto.eddsa [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.commons.codec [1.14.0.v20221112-0806,1.14.0.v20221112-0806] - org.apache.commons.codec.source [1.14.0.v20221112-0806,1.14.0.v20221112-0806] - org.apache.commons.compress [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.compress.source [1.21.0.v20211103-2100,1.21.0.v20211103-2100] - org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] - org.apache.httpcomponents.httpclient [4.5.13.v20221112-0806,4.5.13.v20221112-0806] - org.apache.httpcomponents.httpclient.source [4.5.13.v20221112-0806,4.5.13.v20221112-0806] - org.apache.httpcomponents.httpcore [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.httpcomponents.httpcore.source [4.4.15.v20220209-2345,4.4.15.v20220209-2345] - org.apache.sshd.osgi [2.9.2.v20221117-1942,2.9.2.v20221117-1942] - org.apache.sshd.osgi.source [2.9.2.v20221117-1942,2.9.2.v20221117-1942] - org.apache.sshd.sftp [2.9.2.v20221117-1942,2.9.2.v20221117-1942] - org.apache.sshd.sftp.source [2.9.2.v20221117-1942,2.9.2.v20221117-1942] - org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104] - org.bouncycastle.bcpg [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcpg.source [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcpkix [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcpkix.source [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcprov [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcprov.source [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcutil [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.bouncycastle.bcutil.source [1.72.0.v20221013-1810,1.72.0.v20221013-1810] - org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] - org.mockito.mockito-core [4.8.1.v20221103-2317,4.8.1.v20221103-2317] - org.mockito.mockito-core.source [4.8.1.v20221103-2317,4.8.1.v20221103-2317] - org.objenesis [3.3.0.v20221103-2317,3.3.0.v20221103-2317] - org.objenesis.source [3.3.0.v20221103-2317,3.3.0.v20221103-2317] - org.slf4j.api [1.7.30.v20221112-0806,1.7.30.v20221112-0806] - org.slf4j.api.source [1.7.30.v20221112-0806,1.7.30.v20221112-0806] - org.slf4j.binding.simple [1.7.30.v20221112-0806,1.7.30.v20221112-0806] - org.slf4j.binding.simple.source [1.7.30.v20221112-0806,1.7.30.v20221112-0806] - org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259] - org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20230302014618-2023-03.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20230302014618-2023-03.tpd deleted file mode 100644 index 8578b2c..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20230302014618-2023-03.tpd +++ /dev/null
@@ -1,27 +0,0 @@ -target "R20230302014618-2023-03" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20230302014618/repository" { - com.jcraft.jsch [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jsch.source [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jzlib [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - net.i2p.crypto.eddsa [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.httpcomponents.httpclient [4.5.14.v20221207-1049,4.5.14.v20221207-1049] - org.apache.httpcomponents.httpclient.source [4.5.14.v20221207-1049,4.5.14.v20221207-1049] - org.apache.httpcomponents.httpcore [4.4.16.v20221207-1049,4.4.16.v20221207-1049] - org.apache.httpcomponents.httpcore.source [4.4.16.v20221207-1049,4.4.16.v20221207-1049] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.mockito.mockito-core [4.8.1.v20221103-2317,4.8.1.v20221103-2317] - org.mockito.mockito-core.source [4.8.1.v20221103-2317,4.8.1.v20221103-2317] - org.objenesis [3.3.0.v20221103-2317,3.3.0.v20221103-2317] - org.objenesis.source [3.3.0.v20221103-2317,3.3.0.v20221103-2317] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20230531010532-2023-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20230531010532-2023-06.tpd deleted file mode 100644 index 46055d3..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20230531010532-2023-06.tpd +++ /dev/null
@@ -1,25 +0,0 @@ -target "R20230531010532-2023-06" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/downloads/drops/R20230531010532/repository" { - com.jcraft.jsch [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jsch.source [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jzlib [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - net.i2p.crypto.eddsa [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.httpcomponents.httpclient [4.5.14.v20230516-1249,4.5.14.v20230516-1249] - org.apache.httpcomponents.httpclient.source [4.5.14.v20230516-1249,4.5.14.v20230516-1249] - org.apache.httpcomponents.httpcore [4.4.16.v20221207-1049,4.4.16.v20221207-1049] - org.apache.httpcomponents.httpcore.source [4.4.16.v20221207-1049,4.4.16.v20221207-1049] - org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] - org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] - org.junit [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.junit.source [4.13.2.v20211018-1956,4.13.2.v20211018-1956] - org.objenesis [3.3.0.v20221103-2317,3.3.0.v20221103-2317] - org.objenesis.source [3.3.0.v20221103-2317,3.3.0.v20221103-2317] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.29.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.29.tpd deleted file mode 100644 index 70a17a1..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.29.tpd +++ /dev/null
@@ -1,27 +0,0 @@ -target "orbit-4.29" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/release/4.29.0" { - com.jcraft.jsch [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jsch.source [0.1.55.v20221112-0806,0.1.55.v20221112-0806] - com.jcraft.jzlib [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - com.jcraft.jzlib.source [1.1.3.v20220502-1820,1.1.3.v20220502-1820] - net.i2p.crypto.eddsa [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - net.i2p.crypto.eddsa.source [0.3.0.v20220506-1020,0.3.0.v20220506-1020] - org.apache.ant [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.ant.source [1.10.12.v20211102-1452,1.10.12.v20211102-1452] - org.apache.httpcomponents.httpclient [4.5.14,4.5.14] - org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] - org.apache.httpcomponents.httpcore [4.4.16,4.4.16] - org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.3,3.3] - org.objenesis.source [3.3,3.3] - org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] - org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.31.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.31.tpd deleted file mode 100644 index 0554a85..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.31.tpd +++ /dev/null
@@ -1,27 +0,0 @@ -target "orbit-4.30" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12" { - com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] - com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] - com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - net.i2p.crypto.eddsa [0.3.0,0.3.0] - net.i2p.crypto.eddsa.source [0.3.0,0.3.0] - org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.httpcomponents.httpclient [4.5.14,4.5.14] - org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] - org.apache.httpcomponents.httpcore [4.4.16,4.4.16] - org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.3,3.3] - org.objenesis.source [3.3,3.3] - org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] - org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd similarity index 85% copy from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd copy to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd index 0554a85..59fcd87 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd
@@ -1,13 +1,11 @@ -target "orbit-4.30" with source configurePhase +target "orbit-4.32" with source configurePhase // see https://download.eclipse.org/tools/orbit/downloads/ -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12" { +location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-06" { com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - net.i2p.crypto.eddsa [0.3.0,0.3.0] - net.i2p.crypto.eddsa.source [0.3.0,0.3.0] org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] @@ -20,8 +18,8 @@ org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.3,3.3] - org.objenesis.source [3.3,3.3] + org.objenesis [3.4,3.4] + org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] }
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd similarity index 85% rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd index 0554a85..2cfa0a8 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd
@@ -1,13 +1,11 @@ -target "orbit-4.30" with source configurePhase +target "orbit-4.33" with source configurePhase // see https://download.eclipse.org/tools/orbit/downloads/ -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12" { +location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-09" { com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - net.i2p.crypto.eddsa [0.3.0,0.3.0] - net.i2p.crypto.eddsa.source [0.3.0,0.3.0] org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] @@ -20,8 +18,8 @@ org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.3,3.3] - org.objenesis.source [3.3,3.3] + org.objenesis [3.4,3.4] + org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] }
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd similarity index 68% copy from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd copy to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd index 0554a85..d3e15bb 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd
@@ -1,15 +1,13 @@ -target "orbit-4.30" with source configurePhase +target "orbit-4.34" with source configurePhase // see https://download.eclipse.org/tools/orbit/downloads/ -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12" { +location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-12" { com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - net.i2p.crypto.eddsa [0.3.0,0.3.0] - net.i2p.crypto.eddsa.source [0.3.0,0.3.0] - org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] + org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] @@ -18,10 +16,10 @@ org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.3,3.3] - org.objenesis.source [3.3,3.3] + org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objenesis [3.4,3.4] + org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] }
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd similarity index 68% copy from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd copy to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd index 0554a85..ec6996e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.30.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd
@@ -1,15 +1,13 @@ -target "orbit-4.30" with source configurePhase +target "orbit-4.35" with source configurePhase // see https://download.eclipse.org/tools/orbit/downloads/ -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023-12" { +location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2025-03" { com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - net.i2p.crypto.eddsa [0.3.0,0.3.0] - net.i2p.crypto.eddsa.source [0.3.0,0.3.0] - org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] + org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] @@ -18,10 +16,10 @@ org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.3,3.3] - org.objenesis.source [3.3,3.3] + org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objenesis [3.4,3.4] + org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] }
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index 06cd76c..6352d0a 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml
@@ -16,7 +16,7 @@ <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> <packaging>pom</packaging> <name>JGit Tycho Parent</name> @@ -30,8 +30,8 @@ <properties> <java.version>17</java.version> - <tycho-version>4.0.6</tycho-version> - <target-platform>jgit-4.17</target-platform> + <tycho-version>4.0.11</tycho-version> + <target-platform>jgit-4.32</target-platform> <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp> </properties> @@ -174,7 +174,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> - <version>3.4.1</version> + <version>3.5.0</version> <executions> <execution> <id>enforce-maven</id> @@ -184,7 +184,7 @@ <configuration> <rules> <requireMavenVersion> - <version>3.6.3</version> + <version>3.9.0</version> </requireMavenVersion> </rules> </configuration> @@ -204,7 +204,7 @@ <plugin> <groupId>org.cyclonedx</groupId> <artifactId>cyclonedx-maven-plugin</artifactId> - <version>2.7.11</version> + <version>2.9.1</version> <configuration> <projectType>library</projectType> <schemaVersion>1.4</schemaVersion> @@ -233,7 +233,7 @@ <plugin> <groupId>io.github.git-commit-id</groupId> <artifactId>git-commit-id-maven-plugin</artifactId> - <version>7.0.0</version> + <version>9.0.1</version> <executions> <execution> <id>get-the-git-infos</id> @@ -273,7 +273,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> - <version>3.3.0</version> + <version>3.4.2</version> <configuration> <archive> <manifestEntries> @@ -381,36 +381,36 @@ <plugin> <groupId>org.eclipse.cbi.maven.plugins</groupId> <artifactId>eclipse-jarsigner-plugin</artifactId> - <version>1.4.3</version> + <version>1.5.2</version> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> - <version>3.5.0</version> + <version>3.6.0</version> </plugin> <plugin> <artifactId>maven-clean-plugin</artifactId> - <version>3.3.2</version> + <version>3.4.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> - <version>3.1.1</version> + <version>3.1.3</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> - <version>3.1.1</version> + <version>3.1.3</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> - <version>4.0.0-M13</version> + <version>4.0.0-M16</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-artifact-plugin</artifactId> - <version>3.5.0</version> + <version>3.6.0</version> <configuration> <ignore>**/*cyclonedx.json</ignore> <reproducible>true</reproducible>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF index 955c5c0..2056f0b 100644 --- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -3,30 +3,30 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm.test Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.diff;version="[7.0.0,7.1.0)", - org.eclipse.jgit.dircache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.merge;version="[7.0.0,7.1.0)", - org.eclipse.jgit.pgm;version="[7.0.0,7.1.0)", - org.eclipse.jgit.pgm.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.pgm.opt;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.io;version="[7.0.0,7.1.0)", +Import-Package: org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.diff;version="[7.3.0,7.4.0)", + org.eclipse.jgit.dircache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.merge;version="[7.3.0,7.4.0)", + org.eclipse.jgit.pgm;version="[7.3.0,7.4.0)", + org.eclipse.jgit.pgm.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.pgm.opt;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.io;version="[7.3.0,7.4.0)", org.hamcrest.core;bundle-version="[1.1.0,3.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.rules;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml index 90090d6..24c289c 100644 --- a/org.eclipse.jgit.pgm.test/pom.xml +++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java index 6d6374f..a48fcbc 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Google Inc. and others + * Copyright (C) 2012, 2025 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 @@ -12,7 +12,10 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.File; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.dircache.DirCache; @@ -32,12 +35,7 @@ public void setUp() throws Exception { @Test public void testAddNothing() throws Exception { - try { - execute("git add"); - fail("Must die"); - } catch (Die e) { - // expected, requires argument - } + assertThrows(Die.class, () -> execute("git add")); } @Test @@ -46,6 +44,17 @@ public void testAddUsage() throws Exception { } @Test + public void testAddInvalidOptionCombinations() throws Exception { + writeTrashFile("greeting", "Hello, world!"); + assertThrows(Die.class, () -> execute("git add -u -A greeting")); + assertThrows(Die.class, + () -> execute("git add -u --ignore-removed greeting")); + // --renormalize implies -u + assertThrows(Die.class, + () -> execute("git add --renormalize --all greeting")); + } + + @Test public void testAddAFile() throws Exception { writeTrashFile("greeting", "Hello, world!"); assertArrayEquals(new String[] { "" }, // @@ -78,4 +87,34 @@ public void testAddAlreadyAdded() throws Exception { assertNotNull(cache.getEntry("greeting")); assertEquals(1, cache.getEntryCount()); } + + @Test + public void testAddDeleted() throws Exception { + File greeting = writeTrashFile("greeting", "Hello, world!"); + git.add().addFilepattern("greeting").call(); + DirCache cache = db.readDirCache(); + assertNotNull(cache.getEntry("greeting")); + assertEquals(1, cache.getEntryCount()); + assertTrue(greeting.delete()); + assertArrayEquals(new String[] { "" }, // + execute("git add greeting")); + + cache = db.readDirCache(); + assertEquals(0, cache.getEntryCount()); + } + + @Test + public void testAddDeleted2() throws Exception { + File greeting = writeTrashFile("greeting", "Hello, world!"); + git.add().addFilepattern("greeting").call(); + DirCache cache = db.readDirCache(); + assertNotNull(cache.getEntry("greeting")); + assertEquals(1, cache.getEntryCount()); + assertTrue(greeting.delete()); + assertArrayEquals(new String[] { "" }, // + execute("git add -A")); + + cache = db.readDirCache(); + assertEquals(0, cache.getEntryCount()); + } }
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java index a1fb9fb..c56cc6b 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
@@ -126,7 +126,7 @@ private RevCommit createSecondCommit() throws Exception { JGitTestUtil.writeTrashFile(db, "Test.txt", "Some change"); git.add().addFilepattern("Test.txt").call(); return git.commit() - .setCommitter(new PersonIdent(this.committer, tr.getDate())) + .setCommitter(new PersonIdent(this.committer, tr.getInstant())) .setMessage("Second commit").call(); } @@ -134,7 +134,7 @@ private RevCommit createThirdCommit() throws Exception { JGitTestUtil.writeTrashFile(db, "change.txt", "another change"); git.add().addFilepattern("change.txt").call(); return git.commit() - .setCommitter(new PersonIdent(this.committer, tr.getDate())) + .setCommitter(new PersonIdent(this.committer, tr.getInstant())) .setMessage("Third commit").call(); }
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java index c785443..595767d 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
@@ -123,6 +123,15 @@ public void testDescribeCommitMatch2() throws Exception { } @Test + public void testDescribeExclude() throws Exception { + initialCommitAndTag(); + secondCommit(); + git.tag().setName("v2.0").call(); + assertArrayEquals(new String[] { "v1.0-1-g56f6ceb", "" }, + execute("git describe --exclude v2.*")); + } + + @Test public void testDescribeCommitMultiMatch() throws Exception { initialCommitAndTag(); secondCommit(); @@ -133,6 +142,17 @@ public void testDescribeCommitMultiMatch() throws Exception { } @Test + public void testDescribeCommitMultiExclude() throws Exception { + initialCommitAndTag(); + secondCommit(); + git.tag().setName("v2.0.0").call(); + git.tag().setName("v2.1.1").call(); + git.tag().setName("v2.2").call(); + assertArrayEquals("git yields v2.2", new String[] { "v2.2", "" }, + execute("git describe --exclude v2.0* --exclude v2.1.*")); + } + + @Test public void testDescribeCommitNoMatch() throws Exception { initialCommitAndTag(); writeTrashFile("greeting", "Hello, world!");
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java index 54c4f26..6339831 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java
@@ -27,6 +27,7 @@ import org.eclipse.jgit.internal.diffmergetool.MergeTools; import org.eclipse.jgit.lib.StoredConfig; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; /** @@ -77,6 +78,7 @@ public void testUserToolWithCommandNotFoundError() throws Exception { + errorReturnCode); } + @Ignore @Test public void testEmptyToolName() throws Exception { assumeLinuxPlatform(); @@ -91,7 +93,7 @@ public void testEmptyToolName() throws Exception { createMergeConflict(); - String araxisErrorLine = "compare: unrecognized option `-wait' @ error/compare.c/CompareImageCommand/1123."; + String araxisErrorLine = "compare-im6.q16: unrecognized option `-wait' @ error/compare.c/CompareImageCommand/1131."; String[] expectedErrorOutput = { araxisErrorLine, araxisErrorLine, }; runAndCaptureUsingInitRaw(Arrays.asList(expectedErrorOutput), MERGE_TOOL, "--no-prompt");
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java new file mode 100644 index 0000000..b4d4ea9 --- /dev/null +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/PackRefsTest.java
@@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.eclipse.jgit.lib.CLIRepositoryTestCase; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.junit.Before; +import org.junit.Test; + +public class PackRefsTest extends CLIRepositoryTestCase { + private Git git; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + git = new Git(db); + git.commit().setMessage("initial commit").call(); + } + + @Test + public void tagPacked() throws Exception { + git.tag().setName("test").call(); + git.packRefs().call(); + assertEquals(Ref.Storage.PACKED, + git.getRepository().exactRef("refs/tags/test").getStorage()); + } + + @Test + public void nonTagRefNotPackedWithoutAll() throws Exception { + git.branchCreate().setName("test").call(); + git.packRefs().call(); + assertEquals(Ref.Storage.LOOSE, + git.getRepository().exactRef("refs/heads/test").getStorage()); + } + + @Test + public void nonTagRefPackedWithAll() throws Exception { + git.branchCreate().setName("test").call(); + git.packRefs().setAll(true).call(); + assertEquals(Ref.Storage.PACKED, + git.getRepository().exactRef("refs/heads/test").getStorage()); + } + + @Test + public void refTableCompacted() throws Exception { + ((FileRepository) git.getRepository()).convertRefStorage( + ConfigConstants.CONFIG_REF_STORAGE_REFTABLE, false, false); + + git.commit().setMessage("test commit").call(); + File tableDir = new File(db.getDirectory(), Constants.REFTABLE); + File[] reftables = tableDir.listFiles(); + assertNotNull(reftables); + assertTrue(reftables.length > 2); + + git.packRefs().call(); + + reftables = tableDir.listFiles(); + assertNotNull(reftables); + assertEquals(2, reftables.length); + } +}
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF index bb0c23d..d91efd4 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -14,49 +14,50 @@ org.eclipse.jetty.server.handler;version="[12.0.0,13.0.0)", org.eclipse.jetty.util;version="[12.0.0,13.0.0)", org.eclipse.jetty.util.component;version="[12.0.0,13.0.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.archive;version="[7.0.0,7.1.0)", - org.eclipse.jgit.awtui;version="[7.0.0,7.1.0)", - org.eclipse.jgit.blame;version="[7.0.0,7.1.0)", - org.eclipse.jgit.diff;version="[7.0.0,7.1.0)", - org.eclipse.jgit.dircache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.gitrepo;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.io;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.server;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.server.fs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs.server.s3;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.merge;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.notes;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revplot;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.pack;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http.apache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.resolver;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.ssh.jsch;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.sshd;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.io;version="[7.0.0,7.1.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.archive;version="[7.3.0,7.4.0)", + org.eclipse.jgit.awtui;version="[7.3.0,7.4.0)", + org.eclipse.jgit.blame;version="[7.3.0,7.4.0)", + org.eclipse.jgit.diff;version="[7.3.0,7.4.0)", + org.eclipse.jgit.dircache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.gitrepo;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.io;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.midx;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.server;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.server.fs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs.server.s3;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.merge;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.notes;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revplot;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.pack;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http.apache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.resolver;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.ssh.jsch;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.sshd;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.io;version="[7.3.0,7.4.0)", org.kohsuke.args4j;version="[2.33.0,3.0.0)", org.kohsuke.args4j.spi;version="[2.33.0,3.0.0)" -Export-Package: org.eclipse.jgit.console;version="7.0.0"; +Export-Package: org.eclipse.jgit.console;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util", - org.eclipse.jgit.pgm;version="7.0.0"; + org.eclipse.jgit.pgm;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util.io, org.eclipse.jgit.awtui, @@ -68,14 +69,14 @@ org.eclipse.jgit.treewalk, org.eclipse.jgit.api, javax.swing", - org.eclipse.jgit.pgm.debug;version="7.0.0"; + org.eclipse.jgit.pgm.debug;version="7.3.0"; uses:="org.eclipse.jgit.util.io, org.eclipse.jgit.pgm, org.eclipse.jetty.servlet", - org.eclipse.jgit.pgm.internal;version="7.0.0"; + org.eclipse.jgit.pgm.internal;version="7.3.0"; x-friends:="org.eclipse.jgit.pgm.test, org.eclipse.jgit.test", - org.eclipse.jgit.pgm.opt;version="7.0.0"; + org.eclipse.jgit.pgm.opt;version="7.3.0"; uses:="org.kohsuke.args4j, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk,
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF index 8bb1b64..1c4a481 100644 --- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.pgm - Sources Bundle-SymbolicName: org.eclipse.jgit.pgm.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin index 08d3727..6bf88d9 100644 --- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin +++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -26,6 +26,8 @@ org.eclipse.jgit.pgm.Merge org.eclipse.jgit.pgm.MergeBase org.eclipse.jgit.pgm.MergeTool +org.eclipse.jgit.pgm.MultiPackIndex +org.eclipse.jgit.pgm.PackRefs org.eclipse.jgit.pgm.Push org.eclipse.jgit.pgm.ReceivePack org.eclipse.jgit.pgm.Reflog
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index 7cd76c3..5890ce8 100644 --- a/org.eclipse.jgit.pgm/pom.xml +++ b/org.eclipse.jgit.pgm/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.pgm</artifactId>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index 50ee809..e9630e9 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
@@ -12,6 +12,7 @@ # default meta variable defined in the org.kohsuke.args4j.spi.OneArgumentOptionHandler N=N +addIncompatibleOptions=--update/-u cannot be combined with --all/-A/--no-ignore-removal or --no-all/--ignore-removal. Note that --renormalize implies --update. alreadyOnBranch=Already on ''{0}'' alreadyUpToDate=Already up-to-date. answerNo=n @@ -255,8 +256,11 @@ untrackedFiles=Untracked files: updating=Updating {0}..{1} usage_Abbrev=Instead of using the default number of hexadecimal digits (which will vary according to the number of objects in the repository with a default of 7) of the abbreviated object name, use <n> digits, or as many digits as needed to form a unique object name. An <n> of 0 will suppress long format, only showing the closest tag. -usage_addRenormalize=Apply the "clean" process freshly to tracked files to forcibly add them again to the index. This implies -u. +usage_addRenormalize=Apply the "clean" process freshly to tracked files to forcibly add them again to the index. This implies --update/-u. +usage_addStageDeletions=Add, modify, or remove index entries to match the working tree. Cannot be used with --update/-u. +usage_addDontStageDeletions=Only add or modify index entries, but do not remove index entries for which there is no file. (Don''t stage deletions.) Cannot be used with --update/-u. usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time +usage_All=Pack all refs, except hidden refs, broken refs, and symbolic refs. usage_AlwaysFallback=Show uniquely abbreviated commit object as fallback usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR. usage_extraArgument=Pass an extra argument to a merge driver. Currently supported are "-X ours" and "-X theirs". @@ -278,6 +282,7 @@ usage_Describe=Show the most recent tag that is reachable from a commit usage_DiffAlgorithms=Test performance of jgit's diff algorithms usage_DisplayTheVersionOfJgit=Display the version of jgit +usage_Exclude=Do not consider tags matching the given glob(7) pattern, excluding the "refs/tags/" prefix usage_Gc=Cleanup unnecessary files and optimize the local repository usage_Glog=View commit history as a graph usage_DiffGuiTool=When git-difftool is invoked with the -g or --gui option the default diff tool will be read from the configured diff.guitool variable instead of diff.tool. @@ -299,7 +304,9 @@ usage_Match=Only consider tags matching the given glob(7) pattern or patterns, excluding the "refs/tags/" prefix. usage_MergeBase=Find as good common ancestors as possible for a merge usage_MergesTwoDevelopmentHistories=Merges two development histories +usage_MultiPackIndex=Operations over the multipack index usage_PackKeptObjects=Include objects in packs locked by a ".keep" file when repacking +usage_PackRefs=Pack heads and tags for efficient repository access usage_PreserveOldPacks=Preserve old pack files by moving them into the preserved subdirectory instead of deleting them after repacking usage_PrunePreserved=Remove the preserved subdirectory containing previously preserved old pack files before repacking, and before preserving more old pack files usage_ReadDirCache= Read the DirCache 100 times
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java index 2ebab5e..dc9d77d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> and others + * Copyright (C) 2010, 2025 Sasa Zivkov <sasa.zivkov@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 @@ -16,6 +16,7 @@ import org.eclipse.jgit.api.AddCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.pgm.internal.CLIText; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @@ -28,17 +29,33 @@ class Add extends TextBuiltin { @Option(name = "--update", aliases = { "-u" }, usage = "usage_onlyMatchAgainstAlreadyTrackedFiles") private boolean update = false; - @Argument(required = true, metaVar = "metaVar_filepattern", usage = "usage_filesToAddContentFrom") + @Option(name = "--all", aliases = { "-A", + "--no-ignore-removal" }, usage = "usage_addStageDeletions") + private Boolean all; + + @Option(name = "--no-all", aliases = { + "--ignore-removal" }, usage = "usage_addDontStageDeletions") + private void noAll(@SuppressWarnings("unused") boolean ignored) { + all = Boolean.FALSE; + } + + @Argument(metaVar = "metaVar_filepattern", usage = "usage_filesToAddContentFrom") private List<String> filepatterns = new ArrayList<>(); @Override protected void run() throws Exception { try (Git git = new Git(db)) { - AddCommand addCmd = git.add(); if (renormalize) { update = true; } + if (update && all != null) { + throw die(CLIText.get().addIncompatibleOptions); + } + AddCommand addCmd = git.add(); addCmd.setUpdate(update).setRenormalize(renormalize); + if (all != null) { + addCmd.setAll(all.booleanValue()); + } for (String p : filepatterns) { addCmd.addFilepattern(p); }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java index d2285ae..285fe2a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
@@ -18,7 +18,7 @@ import java.io.IOException; import java.text.MessageFormat; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -91,7 +91,7 @@ void ignoreAllSpace(@SuppressWarnings("unused") boolean on) { private final Map<RevCommit, String> abbreviatedCommits = new HashMap<>(); - private SimpleDateFormat dateFmt; + private DateTimeFormatter dateFmt; private int begin; @@ -125,9 +125,9 @@ protected void run() { } if (showRawTimestamp) { - dateFmt = new SimpleDateFormat("ZZZZ"); //$NON-NLS-1$ + dateFmt = DateTimeFormatter.ofPattern("ZZ"); //$NON-NLS-1$ } else { - dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZZ"); //$NON-NLS-1$ + dateFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss ZZ"); //$NON-NLS-1$ } try (ObjectReader reader = db.newObjectReader(); @@ -335,12 +335,14 @@ private String date(int line) { if (author == null) return ""; //$NON-NLS-1$ - dateFmt.setTimeZone(author.getTimeZone()); - if (!showRawTimestamp) - return dateFmt.format(author.getWhen()); + if (!showRawTimestamp) { + return dateFmt.withZone(author.getZoneId()) + .format(author.getWhenAsInstant()); + } return String.format("%d %s", //$NON-NLS-1$ - Long.valueOf(author.getWhen().getTime() / 1000L), - dateFmt.format(author.getWhen())); + Long.valueOf(author.getWhenAsInstant().getEpochSecond()), + dateFmt.withZone(author.getZoneId()) + .format(author.getWhenAsInstant())); } private String abbreviate(ObjectReader reader, RevCommit commit)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java index 52f40c2..f5de704 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
@@ -94,7 +94,7 @@ private void list() throws IOException, ConfigInvalidException { if (global || isListAll()) list(SystemReader.getInstance().openUserConfig(null, fs)); if (local || isListAll()) - list(new FileBasedConfig(fs.resolve(getRepository().getDirectory(), + list(new FileBasedConfig(fs.resolve(getRepository().getCommonDirectory(), Constants.CONFIG), fs)); }
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 913d7c7..2633336 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -44,6 +44,9 @@ class Describe extends TextBuiltin { @Option(name = "--match", usage = "usage_Match", metaVar = "metaVar_pattern") private List<String> patterns = new ArrayList<>(); + @Option(name = "--exclude", usage = "usage_Exclude", metaVar = "metaVar_pattern") + private List<String> excludes = new ArrayList<>(); + @Option(name = "--abbrev", usage = "usage_Abbrev") private Integer abbrev; @@ -59,6 +62,7 @@ protected void run() { cmd.setTags(useTags); cmd.setAlways(always); cmd.setMatch(patterns.toArray(new String[0])); + cmd.setExclude(excludes.toArray(new String[0])); if (abbrev != null) { cmd.setAbbrev(abbrev.intValue()); }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java index 852a4b3..958e566 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -32,13 +32,12 @@ import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.GpgConfig; -import org.eclipse.jgit.lib.GpgSignatureVerifier; -import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification; -import org.eclipse.jgit.lib.GpgSignatureVerifierFactory; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifiers; import org.eclipse.jgit.notes.NoteMap; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.VerificationUtils; @@ -174,8 +173,6 @@ void noPrefix(@SuppressWarnings("unused") boolean on) { // END -- Options shared with Diff - private GpgSignatureVerifier verifier; - private GpgConfig config; Log() { @@ -227,9 +224,6 @@ protected void run() { throw die(e.getMessage(), e); } finally { diffFmt.close(); - if (verifier != null) { - verifier.clear(); - } } } @@ -293,21 +287,13 @@ private void showSignature(RevCommit c) throws IOException { if (c.getRawGpgSignature() == null) { return; } - if (verifier == null) { - GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory - .getDefault(); - if (factory == null) { - throw die(CLIText.get().logNoSignatureVerifier, null); - } - verifier = factory.getVerifier(); - } - SignatureVerification verification = verifier.verifySignature(c, - config); + SignatureVerification verification = SignatureVerifiers.verify(db, + config, c); if (verification == null) { return; } VerificationUtils.writeVerification(outw, verification, - verifier.getName(), c.getCommitterIdent()); + verification.verifierName(), c.getCommitterIdent()); } /**
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java index aacde2f..a29c4d9 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java
@@ -26,11 +26,6 @@ class MergeBase extends TextBuiltin { private boolean all; @Argument(index = 0, metaVar = "metaVar_commitish", required = true) - void commit_0(final RevCommit c) { - commits.add(c); - } - - @Argument(index = 1, metaVar = "metaVar_commitish", required = true) private List<RevCommit> commits = new ArrayList<>(); @Override
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java new file mode 100644 index 0000000..1844223 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java
@@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.file.ObjectDirectory; +import org.eclipse.jgit.internal.storage.file.Pack; +import org.eclipse.jgit.internal.storage.file.PackFile; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexPrettyPrinter; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +@Command(common = true, usage = "usage_MultiPackIndex") +@SuppressWarnings("nls") +class MultiPackIndex extends TextBuiltin { + @Argument(index = 0, required = true, usage = "write, print") + private String command; + + @Option(name = "--midx") + private String midxPath; + + /** {@inheritDoc} */ + @Override + protected void run() throws IOException { + switch (command) { + case "print": + printMultiPackIndex(); + break; + case "write": + writeMultiPackIndex(); + break; + default: + outw.println("Unknown command " + command); + } + } + + private void printMultiPackIndex() { + if (midxPath == null || midxPath.isEmpty()) { + throw die("'print' requires the path of a multipack " + + "index file with --midx option."); + } + + try (FileInputStream is = new FileInputStream(midxPath)) { + PrintWriter pw = new PrintWriter(outw, true); + MultiPackIndexPrettyPrinter.prettyPrint(is.readAllBytes(), pw); + } catch (FileNotFoundException e) { + throw die(true, e); + } catch (IOException e) { + throw die(true, e); + } + } + + private void writeMultiPackIndex() throws IOException { + if (!(db.getObjectDatabase() instanceof ObjectDirectory)) { + throw die("This repository object db doesn't have packs"); + } + + File midx; + if (midxPath == null || midxPath.isEmpty()) { + midx = new File(((ObjectDirectory) db.getObjectDatabase()) + .getPackDirectory(), "multi-pack-index"); + } else { + midx = new File(midxPath); + } + + errw.println("Writing " + midx.getAbsolutePath()); + + ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); + + Map<String, PackIndex> indexes = new HashMap<>(); + for (Pack pack : odb.getPacks()) { + PackFile packFile = pack.getPackFile().create(PackExt.INDEX); + try { + indexes.put(packFile.getName(), pack.getIndex()); + } catch (IOException e) { + throw die("Cannot open index in pack", e); + } + } + + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + try (FileOutputStream out = new FileOutputStream(midxPath)) { + writer.write(NullProgressMonitor.INSTANCE, out, indexes); + } catch (IOException e) { + throw die("Cannot write midx " + midxPath, e); + } + } +}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java new file mode 100644 index 0000000..ee05f5c --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/PackRefs.java
@@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.pgm; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.kohsuke.args4j.Option; + +@Command(common = true, usage = "usage_PackRefs") +class PackRefs extends TextBuiltin { + @Option(name = "--all", usage = "usage_All") + private boolean all; + + @Override + protected void run() { + Git git = Git.wrap(db); + try { + git.packRefs().setProgressMonitor(new TextProgressMonitor(errw)) + .setAll(all).call(); + } catch (GitAPIException e) { + throw die(e.getMessage(), e); + } + } +}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java index 4feb090..a3a6782 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
@@ -14,11 +14,10 @@ import java.io.BufferedOutputStream; import java.io.IOException; -import java.text.DateFormat; import java.text.MessageFormat; -import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Locale; -import java.util.TimeZone; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawTextComparator; @@ -30,12 +29,11 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.GpgConfig; -import org.eclipse.jgit.lib.GpgSignatureVerifier; -import org.eclipse.jgit.lib.GpgSignatureVerifierFactory; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.SignatureVerifiers; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.VerificationUtils; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; @@ -52,9 +50,9 @@ @Command(common = true, usage = "usage_show") class Show extends TextBuiltin { - private final TimeZone myTZ = TimeZone.getDefault(); + private final ZoneId myTZ = ZoneId.systemDefault(); - private final DateFormat fmt; + private final DateTimeFormatter fmt; private DiffFormatter diffFmt; @@ -158,7 +156,8 @@ void noPrefix(@SuppressWarnings("unused") boolean on) { // END -- Options shared with Diff Show() { - fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US); //$NON-NLS-1$ + fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy ZZ", //$NON-NLS-1$ + Locale.US); } @Override @@ -233,15 +232,17 @@ private void show(RevTag tag) throws IOException { outw.print(tag.getTagName()); outw.println(); - final PersonIdent tagger = tag.getTaggerIdent(); + PersonIdent tagger = tag.getTaggerIdent(); if (tagger != null) { outw.println(MessageFormat.format(CLIText.get().taggerInfo, tagger.getName(), tagger.getEmailAddress())); - final TimeZone taggerTZ = tagger.getTimeZone(); - fmt.setTimeZone(taggerTZ != null ? taggerTZ : myTZ); + ZoneId taggerTZ = tagger.getZoneId(); + String formattedTaggerTime = fmt + .withZone(taggerTZ != null ? taggerTZ : myTZ) + .format(tagger.getWhenAsInstant()); outw.println(MessageFormat.format(CLIText.get().dateInfo, - fmt.format(tagger.getWhen()))); + formattedTaggerTime)); } outw.println(); @@ -294,10 +295,12 @@ private void show(RevWalk rw, RevCommit c) throws IOException { outw.println(MessageFormat.format(CLIText.get().authorInfo, author.getName(), author.getEmailAddress())); - final TimeZone authorTZ = author.getTimeZone(); - fmt.setTimeZone(authorTZ != null ? authorTZ : myTZ); + final ZoneId authorTZ = author.getZoneId(); + String formattedAuthorTime = fmt + .withZone(authorTZ != null ? authorTZ : myTZ) + .format(author.getWhenAsInstant()); outw.println(MessageFormat.format(CLIText.get().dateInfo, - fmt.format(author.getWhen()))); + formattedAuthorTime)); outw.println(); final String[] lines = c.getFullMessage().split("\n"); //$NON-NLS-1$ @@ -335,23 +338,13 @@ private void showSignature(RevCommit c) throws IOException { if (c.getRawGpgSignature() == null) { return; } - GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory - .getDefault(); - if (factory == null) { + GpgConfig config = new GpgConfig(db.getConfig()); + SignatureVerification verification = SignatureVerifiers.verify(db, + config, c); + if (verification == null) { throw die(CLIText.get().logNoSignatureVerifier, null); } - GpgSignatureVerifier verifier = factory.getVerifier(); - GpgConfig config = new GpgConfig(db.getConfig()); - try { - SignatureVerification verification = verifier.verifySignature(c, - config); - if (verification == null) { - return; - } - VerificationUtils.writeVerification(outw, verification, - verifier.getName(), c.getCommitterIdent()); - } finally { - verifier.clear(); - } + VerificationUtils.writeVerification(outw, verification, + verification.verifierName(), c.getCommitterIdent()); } }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java index 4ea67ab..6be30c9 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -27,10 +27,10 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.VerificationUtils; import org.eclipse.jgit.revwalk.RevCommit; @@ -106,7 +106,8 @@ protected void run() { if (error != null) { throw die(error.getMessage(), error); } - writeVerification(verifySig.getVerifier().getName(), + writeVerification( + verification.getVerification().verifierName(), (RevTag) verification.getObject(), verification.getVerification()); }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java index 2f96ef7..22d9e34 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
@@ -18,8 +18,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.text.MessageFormat; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.ListIterator; @@ -166,7 +166,8 @@ private void recreateCommitGraph() throws IOException { final CommitBuilder newc = new CommitBuilder(); newc.setTreeId(emptyTree); - newc.setAuthor(new PersonIdent(me, new Date(t.commitTime))); + newc.setAuthor(new PersonIdent(me, + Instant.ofEpochSecond(t.commitTime))); newc.setCommitter(newc.getAuthor()); newc.setParentIds(newParents); newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java index c95f138..74e322f 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
@@ -31,6 +31,7 @@ import org.eclipse.jgit.pgm.TextBuiltin; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.util.TemporaryBuffer; import org.kohsuke.args4j.Argument; @@ -68,7 +69,7 @@ protected void run() throws Exception { ObjectReuseAsIs asis = (ObjectReuseAsIs) reader; ObjectToPack target = asis.newObjectToPack(obj, obj.getType()); - PackWriter pw = new PackWriter(reader) { + PackWriter pw = new PackWriter(new PackConfig(), reader) { @Override public void select(ObjectToPack otp, StoredObjectRepresentation next) { otp.select(next);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java index faa2bce..7aff2dd 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java
@@ -24,6 +24,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -209,14 +211,15 @@ private static List<LogEntry> readLog(String logPath) } String ref = m.group(1); double t = Double.parseDouble(m.group(2)); - long time = ((long) t) * 1000L; + Instant time = Instant.ofEpochSecond((long) t); long index = (long) (t * 1e6); String user = m.group(3); ObjectId oldId = parseId(m.group(4)); ObjectId newId = parseId(m.group(5)); String msg = m.group(6); String email = user + "@gerrit"; //$NON-NLS-1$ - PersonIdent who = new PersonIdent(user, email, time, -480); + PersonIdent who = new PersonIdent(user, email, time, + ZoneOffset.ofHours(-8)); log.add(new LogEntry(ref, index, who, oldId, newId, msg)); } }
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java index b5bf6d2..bb1e950 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
@@ -1,6 +1,6 @@ /* * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com> - * Copyright (C) 2013, 2021 Obeo and others + * Copyright (C) 2013, 2025 Obeo and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -91,6 +91,7 @@ public static String fatalError(String message) { } // @formatter:off + /***/ public String addIncompatibleOptions; /***/ public String alreadyOnBranch; /***/ public String alreadyUpToDate; /***/ public String answerNo;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java index c1f8a86..64ee602 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/VerificationUtils.java
@@ -11,7 +11,7 @@ import java.io.IOException; -import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.util.GitDateFormatter; import org.eclipse.jgit.util.SignatureUtils;
diff --git a/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF index ad01640..8942a41 100644 --- a/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF
@@ -2,16 +2,16 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent;singleton:=true -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/agent Bundle-Vendor: %Bundle-Vendor -Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[7.0.0,7.1.0)" +Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[7.3.0,7.4.0)" Bundle-ActivationPolicy: lazy Automatic-Module-Name: org.eclipse.jgit.ssh.apache.agent Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.eclipse.jgit.transport.sshd;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)" +Import-Package: org.eclipse.jgit.transport.sshd;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)" Require-Bundle: com.sun.jna;bundle-version="[5.8.0,6.0.0)", com.sun.jna.platform;bundle-version="[5.8.0,6.0.0)" -Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="7.0.0";x-internal:=true +Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="7.3.0";x-internal:=true
diff --git a/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF index 684ab70..37b442e 100644 --- a/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.ssh.apache.agent - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache.agent/pom.xml b/org.eclipse.jgit.ssh.apache.agent/pom.xml index f407ce1..2d34495 100644 --- a/org.eclipse.jgit.ssh.apache.agent/pom.xml +++ b/org.eclipse.jgit.ssh.apache.agent/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache.agent</artifactId>
diff --git a/org.eclipse.jgit.ssh.apache.test/.classpath b/org.eclipse.jgit.ssh.apache.test/.classpath index 6fdb99a..5be47af 100644 --- a/org.eclipse.jgit.ssh.apache.test/.classpath +++ b/org.eclipse.jgit.ssh.apache.test/.classpath
@@ -11,5 +11,10 @@ <attribute name="test" value="true"/> </attributes> </classpathentry> + <classpathentry kind="src" path="tst-rsrc"> + <attributes> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> <classpathentry kind="output" path="bin"/> </classpath>
diff --git a/org.eclipse.jgit.ssh.apache.test/.gitattributes b/org.eclipse.jgit.ssh.apache.test/.gitattributes new file mode 100644 index 0000000..b5b9375 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/.gitattributes
@@ -0,0 +1,2 @@ +/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/repo.bundle binary +/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl* binary
diff --git a/org.eclipse.jgit.ssh.apache.test/BUILD b/org.eclipse.jgit.ssh.apache.test/BUILD index b384464..bf796c0 100644 --- a/org.eclipse.jgit.ssh.apache.test/BUILD +++ b/org.eclipse.jgit.ssh.apache.test/BUILD
@@ -1,19 +1,51 @@ load( + "@com_googlesource_gerrit_bazlets//tools:genrule2.bzl", + "genrule2", +) +load( "@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests", ) +DEPS = [ + "//lib:bcpkix", + "//lib:bcprov", + "//lib:bcutil", + "//lib:junit", + "//lib:slf4j-api", + "//lib:sshd-osgi", + "//lib:sshd-sftp", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.junit:junit", + "//org.eclipse.jgit.junit.ssh:junit-ssh", + "//org.eclipse.jgit.ssh.apache:ssh-apache", +] + +HELPERS = ["tst/org/eclipse/jgit/internal/signing/ssh/AbstractSshSignatureTest.java"] + junit_tests( name = "sshd_apache", - srcs = glob(["tst/**/*.java"]), + srcs = glob( + ["tst/**/*.java"], + exclude = HELPERS, + ), tags = ["sshd"], - deps = [ - "//lib:eddsa", - "//lib:junit", - "//lib:sshd-osgi", - "//lib:sshd-sftp", - "//org.eclipse.jgit:jgit", - "//org.eclipse.jgit.junit.ssh:junit-ssh", - "//org.eclipse.jgit.ssh.apache:ssh-apache", + runtime_deps = [":tst_rsrc"], + deps = DEPS + [ + ":helpers", ], ) + +java_library( + name = "helpers", + testonly = 1, + srcs = HELPERS, + deps = DEPS, +) + +genrule2( + name = "tst_rsrc", + srcs = glob(["tst-rsrc/**"]), + outs = ["tst_rsrc.jar"], + cmd = "tar cf - $(SRCS) | tar -C $$TMP --strip-components=2 -xf - && cd $$TMP && zip -qr $$ROOT/$@ .", +)
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 54d610a..88ab277 100644 --- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -3,35 +3,47 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" -Import-Package: org.apache.sshd.client.config.hosts;version="[2.12.0,2.13.0)", - org.apache.sshd.common;version="[2.12.0,2.13.0)", - org.apache.sshd.common.auth;version="[2.12.0,2.13.0)", - org.apache.sshd.common.config.keys;version="[2.12.0,2.13.0)", - org.apache.sshd.common.helpers;version="[2.12.0,2.13.0)", - org.apache.sshd.common.kex;version="[2.12.0,2.13.0)", - org.apache.sshd.common.keyprovider;version="[2.12.0,2.13.0)", - org.apache.sshd.common.session;version="[2.12.0,2.13.0)", - org.apache.sshd.common.signature;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.net;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.security;version="[2.12.0,2.13.0)", - org.apache.sshd.core;version="[2.12.0,2.13.0)", - org.apache.sshd.server;version="[2.12.0,2.13.0)", - org.apache.sshd.server.forward;version="[2.12.0,2.13.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.sshd.proxy;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit.ssh;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.sshd;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.sshd.agent;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", +Import-Package: org.apache.sshd.certificate;version="[2.15.0,2.16.0)", + org.apache.sshd.client.config.hosts;version="[2.15.0,2.16.0)", + org.apache.sshd.common;version="[2.15.0,2.16.0)", + org.apache.sshd.common.auth;version="[2.15.0,2.16.0)", + org.apache.sshd.common.cipher;version="[2.15.0,2.16.0)", + org.apache.sshd.common.config.keys;version="[2.15.0,2.16.0)", + org.apache.sshd.common.helpers;version="[2.15.0,2.16.0)", + org.apache.sshd.common.kex;version="[2.15.0,2.16.0)", + org.apache.sshd.common.keyprovider;version="[2.15.0,2.16.0)", + org.apache.sshd.common.session;version="[2.15.0,2.16.0)", + org.apache.sshd.common.signature;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.buffer;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.net;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.security;version="[2.15.0,2.16.0)", + org.apache.sshd.core;version="[2.15.0,2.16.0)", + org.apache.sshd.server;version="[2.15.0,2.16.0)", + org.apache.sshd.server.forward;version="[2.15.0,2.16.0)", + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.signing.ssh;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.sshd;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.sshd.proxy;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit.ssh;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.sshd;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.sshd.agent;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", - org.junit.runner;version="[4.13,5.0.0)" + org.junit.rules;version="[4.13.0,5.0.0)", + org.junit.runner;version="[4.13,5.0.0)", + org.junit.runners;version="[4.13.0,5.0.0)", + org.slf4j;version="[1.7.0,3.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml index 967b781..b86a560 100644 --- a/org.eclipse.jgit.ssh.apache.test/pom.xml +++ b/org.eclipse.jgit.ssh.apache.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId> @@ -91,6 +91,12 @@ <sourceDirectory>src/</sourceDirectory> <testSourceDirectory>tst/</testSourceDirectory> + <testResources> + <testResource> + <directory>tst-rsrc/</directory> + </testResource> + </testResources> + <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId>
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/allowed_signers b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/allowed_signers new file mode 100644 index 0000000..ec74409 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/allowed_signers
@@ -0,0 +1,2 @@ +tester@example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO +*@example.com cert-authority ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMdEl+iOTEbf1RC3uicECtid+SaIMsAw7wrlWhOQTyBV
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key new file mode 100644 index 0000000..b8de8c3 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDHRJfojkxG39UQt7onBArYnfkmiDLAMO8K5VoTkE8gVQAAAJAhCMgzIQjI +MwAAAAtzc2gtZWQyNTUxOQAAACDHRJfojkxG39UQt7onBArYnfkmiDLAMO8K5VoTkE8gVQ +AAAEBmcXpast20+B4IzA0Xex2CKYiiWJj3NFJ5F0kil113vcdEl+iOTEbf1RC3uicECtid ++SaIMsAw7wrlWhOQTyBVAAAADVRIV09AU0VBR044MDA= +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key.pub new file mode 100644 index 0000000..842415b --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMdEl+iOTEbf1RC3uicECtid+SaIMsAw7wrlWhOQTyBV
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key2 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key2 new file mode 100644 index 0000000..a4af047 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key2
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACA7S4ycIB6oTx4UN8l9N+u016UgMzkrbT7E+2XbG35jgwAAAJAa2jfBGto3 +wQAAAAtzc2gtZWQyNTUxOQAAACA7S4ycIB6oTx4UN8l9N+u016UgMzkrbT7E+2XbG35jgw +AAAEBothGMqFaA5aTO8MLx9wm1oDRfzQCSsu7uJwrOiUFTTTtLjJwgHqhPHhQ3yX0367TX +pSAzOSttPsT7ZdsbfmODAAAADVRIV09AU0VBR044MDA= +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key2.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key2.pub new file mode 100644 index 0000000..e46c87e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/ca_key2.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDtLjJwgHqhPHhQ3yX0367TXpSAzOSttPsT7ZdsbfmOD
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/expired.cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/expired.cert new file mode 100644 index 0000000..9da63ec --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/expired.cert
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAINFZ5NKywAWh1G1P6BiBKArmYKs1BDhJBOawJKlS29VXAAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzOAAAAAAAAAAEAAAABAAAADGV4cGlyZWRfY2VydAAAAAAAAAAAZtOugAAAAABm1QAAAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgx0SX6I5MRt/VELe6JwQK2J35JogywDDvCuVaE5BPIFUAAABTAAAAC3NzaC1lZDI1NTE5AAAAQNf8i5dhRqWRe06epIRrZ5V+QZHq3ZrlJtlx98UJya9GAeCrJ5oHwBjr5O5TL5wNJS5Hz+T1qsJNFU9d1wdcuwI=
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/no_principals.cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/no_principals.cert new file mode 100644 index 0000000..101e374 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/no_principals.cert
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAILzuED1RSloB/enTghTEKSACVOuEARP0f8UVXSRwEXN6AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzOAAAAAAAAAAIAAAABAAAADW5vX3ByaW5jaXBhbHMAAAAAAAAAAGbTroAAAAAAZyLIgAAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIMdEl+iOTEbf1RC3uicECtid+SaIMsAw7wrlWhOQTyBVAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEBwEQ2D0OHn4QDHnsINlgWUWpmhukseQCJu3Adulz28fFtewp1LLqkBy50wR6vJe1ifYbY4hzReXOSyoTmHSXEN
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/other-ca.cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/other-ca.cert new file mode 100644 index 0000000..752fee1 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/other-ca.cert
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIHNW2bzSS61lvgHippv3Ymx4cVEAXBVCb8lFXHnVpsSyAAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzOAAAAAAAAAAYAAAABAAAAB3Rlc3RlcjIAAAAWAAAAEnRlc3RlckBleGFtcGxlLmNvbQAAAABm066AAAAAAGciyIAAAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACA7S4ycIB6oTx4UN8l9N+u016UgMzkrbT7E+2XbG35jgwAAAFMAAAALc3NoLWVkMjU1MTkAAABAuJ8zBazcaYTbUEr9QtoYox0MkVBg+8LANxJxc885M2vmg9yPHpTfV/emupqhBwuYcPJSskTxl7WX4TUNvhMsAA==
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/other.cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/other.cert new file mode 100644 index 0000000..15825f6 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/other.cert
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIGKXzyrvDzj9ObQ4SuzqytK6nomOV8DhgdzODfWuup1sAAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzOAAAAAAAAAAQAAAABAAAABW90aGVyAAAAFQAAABFvdGhlckBleGFtcGxlLmNvbQAAAABm066AAAAAAGciyIAAAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACDHRJfojkxG39UQt7onBArYnfkmiDLAMO8K5VoTkE8gVQAAAFMAAAALc3NoLWVkMjU1MTkAAABA1ycFqWehyC6pIISEkXSTtHbatLWl9HHAoUFouQiDdubAnMDRSkyHipXR62rq+8yEAvtqm1mXBzO8nLalkF9xAA==
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/tester.cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/tester.cert new file mode 100644 index 0000000..a2b241c --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/tester.cert
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAICSl1xsyTWb23YlKo21musxOzj4L4eD2coTkHbBw2uOyAAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzOAAAAAAAAAAMAAAABAAAABnRlc3RlcgAAABYAAAASdGVzdGVyQGV4YW1wbGUuY29tAAAAAGbTroAAAAAAZyLIgAAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIMdEl+iOTEbf1RC3uicECtid+SaIMsAw7wrlWhOQTyBVAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEDyjzq/0Egm1OxwrvqPZKUihE3w357Ji9Nd3j7VnUuvSYTXAdB9P0E+a2hyCcemmsil1MsvWTiCSSOsrHVB6FEO
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/two_principals.cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/two_principals.cert new file mode 100644 index 0000000..5f7164a --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/certs/two_principals.cert
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIFmWKr9gNSQT0vna7k3uOyUF9CTcMGw2zxTFBf2Ev8TzAAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzOAAAAAAAAAAgAAAABAAAABnRlc3RlcgAAACkAAAAPZm9vQGV4YW1wbGUuY29tAAAAEnRlc3RlckBleGFtcGxlLmNvbQAAAABm066AAAAAAGciyIAAAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACDHRJfojkxG39UQt7onBArYnfkmiDLAMO8K5VoTkE8gVQAAAFMAAAALc3NoLWVkMjU1MTkAAABAqlSX2GzLz5U+hN/gF9UUyAkE6h5BgVFYhsyf1MR/B7Hoxa29wGLbJpUplrqEHMxoud2zfH2Nhj00unc3lr5bBA== ./signing_key.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl new file mode 100644 index 0000000..9469340 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-all b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-all new file mode 100644 index 0000000..6f744c3 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-all Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-ca b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-ca new file mode 100644 index 0000000..84a8bc6 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-ca Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-cert b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-cert new file mode 100644 index 0000000..26f29b2 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-cert Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-empty b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-empty new file mode 100644 index 0000000..78e5187 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-empty Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-hash b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-hash new file mode 100644 index 0000000..cdd1351 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-hash Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keyid b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keyid new file mode 100644 index 0000000..1a65243 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keyid Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keyid-wild b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keyid-wild new file mode 100644 index 0000000..9ba549f --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keyid-wild Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keys b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keys new file mode 100644 index 0000000..8dd496d --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-keys Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-serial b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-serial new file mode 100644 index 0000000..9965e2e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-serial Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-serial-wild b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-serial-wild new file mode 100644 index 0000000..aefd2b1 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-serial-wild Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-sha1 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-sha1 new file mode 100644 index 0000000..3928543 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-sha1 Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-sha256 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-sha256 new file mode 100644 index 0000000..cdd1351 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-sha256 Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-text b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-text new file mode 100644 index 0000000..77ddd5e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/krl-text
@@ -0,0 +1,11 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC29QZ72HtyCdaNo6p2GH3fJpUynwkvs8Acwn66G7YTh +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0ZC4fqgbBgROeX1sOEPr4uMVNfPdJ62bVo/zvSMRQx +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG5IH9T7FY47VJDUoyOlB/iqCN4pO8dgOrxclmKN5R5w +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINjhG4+EnQy8YHLsfE8+IQwNWZVn1GBYX75pwxBCZGmy +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXm+qgTs+sO+9zvoZBxkQD39R2rQqQCVezxQoGjKui5 +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL8+aQKja+SbqxfWR61FCcsbBw2jaF/KHvcqdP2Fbp6Q +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAOL7IULalT2Izo9TgRf1t2HNpZ5WCZJH5oRCd9LK3BN +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGVaSedhPkl2Hrx1nOOKT2E52ADsBebawws87NN1+P6e +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxyaxj7pRVDeh/gxJem9BLhoUQKGnKXHfDrB/GtC1KB +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID96GKtj4wN+OwvrQsgP37fQVUXThCML796qqFNLVDCA +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEh3BFcTzXmg1Fi5LvWiUDWORsHzVhUCm8ekrEJG6+6A
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001 new file mode 100644 index 0000000..893fd5e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAtvUGe9h7cgnWjaOqdhh93yaVMp8JL7PAHMJ+uhu2E4QAAAIhUa4KiVGuC +ogAAAAtzc2gtZWQyNTUxOQAAACAtvUGe9h7cgnWjaOqdhh93yaVMp8JL7PAHMJ+uhu2E4Q +AAAECKgy+3FBgpdfxjOtNy9TamhadMWSyPlPiwu06mYVReyS29QZ72HtyCdaNo6p2GH3fJ +pUynwkvs8Acwn66G7YThAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001-cert.pub new file mode 100644 index 0000000..e2bcd25 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIE1UUsQ+sncsuST6eGe3B5Se7purqhGcWrkyIwUnQM/jAAAAIC29QZ72HtyCdaNo6p2GH3fJpUynwkvs8Acwn66G7YThAAAAAAAAAAEAAAABAAAACXJldm9rZWQgMQAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgFtF5l68spzOFrIpQANF0C9nkNdXMAmlCRwHgw91C784AAABTAAAAC3NzaC1lZDI1NTE5AAAAQCjDATJVQs3odl9fsqaxyx/18qrodZEDyYZAsdqg0GMx8CvLYt4xHENyVm7kyBRxOeh3EKfII0WFoYCV4mGZ/wU= ./tst-keys/revoked-0001.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001.pub new file mode 100644 index 0000000..f561982 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0001.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC29QZ72HtyCdaNo6p2GH3fJpUynwkvs8Acwn66G7YTh
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004 new file mode 100644 index 0000000..e50a4fe --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACC9GQuH6oGwYETnl9bDhD6+LjFTXz3Setm1aP870jEUMQAAAIiQzZzikM2c +4gAAAAtzc2gtZWQyNTUxOQAAACC9GQuH6oGwYETnl9bDhD6+LjFTXz3Setm1aP870jEUMQ +AAAEBpn5dxbvHhqAsSVN3IqRwzbFFgOhdmpkOP+nvoKq+rSr0ZC4fqgbBgROeX1sOEPr4u +MVNfPdJ62bVo/zvSMRQxAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004-cert.pub new file mode 100644 index 0000000..8e92fa7 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIC5jMLPDlEVbyPU/Icb04BF5jxN+OT8kpuO5c0CV6/AYAAAAIL0ZC4fqgbBgROeX1sOEPr4uMVNfPdJ62bVo/zvSMRQxAAAAAAAAAAQAAAABAAAACXJldm9rZWQgNAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgFtF5l68spzOFrIpQANF0C9nkNdXMAmlCRwHgw91C784AAABTAAAAC3NzaC1lZDI1NTE5AAAAQOH4yNn7+zyvsCV8BCoop5xYv4uFk27VZRjmscuy3J66KNwLay9XkvkRNArDaWBwH47dmkcU7F6fLLpY4vN2jgM= ./tst-keys/revoked-0004.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004.pub new file mode 100644 index 0000000..1d7fe7f --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0004.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0ZC4fqgbBgROeX1sOEPr4uMVNfPdJ62bVo/zvSMRQx
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010 new file mode 100644 index 0000000..fb457df --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBuSB/U+xWOO1SQ1KMjpQf4qgjeKTvHYDq8XJZijeUecAAAAIgvtSiML7Uo +jAAAAAtzc2gtZWQyNTUxOQAAACBuSB/U+xWOO1SQ1KMjpQf4qgjeKTvHYDq8XJZijeUecA +AAAECI2si7/SGjMM1UyhrFPXx4laQIfFUsb1+yfXKwQyeOXW5IH9T7FY47VJDUoyOlB/iq +CN4pO8dgOrxclmKN5R5wAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010-cert.pub new file mode 100644 index 0000000..9492f88 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIN2arXaBzVIdxAFfU+XU1Uc788HKlDH3tOLdDtcoORLmAAAAIG5IH9T7FY47VJDUoyOlB/iqCN4pO8dgOrxclmKN5R5wAAAAAAAAAAoAAAABAAAACnJldm9rZWQgMTAAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEDwhgQsYOG/eKf8EfH+fAmEW+88/ZJCmxAExEFPxkGL59waZcGiOJqquTKiqN5Kod8hpUrvZywrA0tjrRkYw8wH ./tst-keys/revoked-0010.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010.pub new file mode 100644 index 0000000..37a0d84 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0010.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG5IH9T7FY47VJDUoyOlB/iqCN4pO8dgOrxclmKN5R5w
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050 new file mode 100644 index 0000000..b02e9df --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDY4RuPhJ0MvGBy7HxPPiEMDVmVZ9RgWF++acMQQmRpsgAAAIgCZLe5AmS3 +uQAAAAtzc2gtZWQyNTUxOQAAACDY4RuPhJ0MvGBy7HxPPiEMDVmVZ9RgWF++acMQQmRpsg +AAAEB9Q6rpWK04mQDoeKSB2I7p/rb8pu00ClhR+vRATl4TYdjhG4+EnQy8YHLsfE8+IQwN +WZVn1GBYX75pwxBCZGmyAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050-cert.pub new file mode 100644 index 0000000..90bb86f --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIIecNj2Es6VfyCrhol4swP9lutvphd3seh+/b2LpD0EsAAAAINjhG4+EnQy8YHLsfE8+IQwNWZVn1GBYX75pwxBCZGmyAAAAAAAAADIAAAABAAAACnJldm9rZWQgNTAAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEA2q8tCXV8FXkB0QWnFNWfCL7zz5jCXL9ZQADM1DaGi8oUU/dxmlQtWgMxuu5vNuvOYQGPDcBLj+by8VqAdvZMP ./tst-keys/revoked-0050.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050.pub new file mode 100644 index 0000000..f3ad249 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0050.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINjhG4+EnQy8YHLsfE8+IQwNWZVn1GBYX75pwxBCZGmy
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090 new file mode 100644 index 0000000..efa3d5e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCV5vqoE7PrDvvc76GQcZEA9/Udq0KkAlXs8UKBoyrouQAAAIg3mgznN5oM +5wAAAAtzc2gtZWQyNTUxOQAAACCV5vqoE7PrDvvc76GQcZEA9/Udq0KkAlXs8UKBoyrouQ +AAAEAkRynGUH9n5hcp/S1WALvuIEDtbkMi2A7yNWze0o4gWpXm+qgTs+sO+9zvoZBxkQD3 +9R2rQqQCVezxQoGjKui5AAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090-cert.pub new file mode 100644 index 0000000..26e61e0 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIOjIztpPiaKY0hztHWtWpX+4LEoyy8qYPPT277K3bykSAAAAIJXm+qgTs+sO+9zvoZBxkQD39R2rQqQCVezxQoGjKui5AAAAAAAAAFoAAAABAAAACnJldm9rZWQgOTAAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEBUaAWyv/jZrbrCO5zw2HuZcWYBig8R2jdvkKr5yzWMWEVRtn97gnAUsIGxkgUnUAs3B2En2FH2NaicC1F1n3sF ./tst-keys/revoked-0090.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090.pub new file mode 100644 index 0000000..e51b88c --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0090.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXm+qgTs+sO+9zvoZBxkQD39R2rQqQCVezxQoGjKui5
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500 new file mode 100644 index 0000000..900d444 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACC/PmkCo2vkm6sX1ketRQnLGwcNo2hfyh73KnT9hW6ekAAAAIhDam0PQ2pt +DwAAAAtzc2gtZWQyNTUxOQAAACC/PmkCo2vkm6sX1ketRQnLGwcNo2hfyh73KnT9hW6ekA +AAAED606GrYWlY7TOXcr8vAr3fjMtCtetdpwFHi2pzgf2Bbb8+aQKja+SbqxfWR61FCcsb +Bw2jaF/KHvcqdP2Fbp6QAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500-cert.pub new file mode 100644 index 0000000..0709618 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIIEblAg4b1eJ5KnT7KvYoOfe24La+nAKKLIYdsR6CdreAAAAIL8+aQKja+SbqxfWR61FCcsbBw2jaF/KHvcqdP2Fbp6QAAAAAAAAAfQAAAABAAAAC3Jldm9rZWQgNTAwAAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABAc0WEuRfi9LG9uTfKY4Dh5MJCHUG7Dqp1J4S4Gs1iOzFX2YKgYXc0O+9j3jJ5/fB4z960Y1AxYR4TWEo1pNjzBQ== ./tst-keys/revoked-0500.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500.pub new file mode 100644 index 0000000..13d1aa4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0500.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL8+aQKja+SbqxfWR61FCcsbBw2jaF/KHvcqdP2Fbp6Q
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510 new file mode 100644 index 0000000..a58675e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACADi+yFC2pU9iM6PU4EX9bdhzaWeVgmSR+aEQnfSytwTQAAAIgigF2AIoBd +gAAAAAtzc2gtZWQyNTUxOQAAACADi+yFC2pU9iM6PU4EX9bdhzaWeVgmSR+aEQnfSytwTQ +AAAEBWpyFpK0a+cdNPFMsvHTHtjBJpX4aMHxBAcEPN8hnpWAOL7IULalT2Izo9TgRf1t2H +NpZ5WCZJH5oRCd9LK3BNAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510-cert.pub new file mode 100644 index 0000000..1431af3 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAII8u8ho0YtDyXWYKv4WeOXSaRUxU8sUV0dQujB2J9VLaAAAAIAOL7IULalT2Izo9TgRf1t2HNpZ5WCZJH5oRCd9LK3BNAAAAAAAAAf4AAAABAAAAC3Jldm9rZWQgNTEwAAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABA3aijJnt8mJ8vLtr7H2PBVJHtNJpL6MQZNXHC6svzygIqZwEq3tDHGR00TPHaCYAqDEXQZysONciOQtQHzKXuBw== ./tst-keys/revoked-0510.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510.pub new file mode 100644 index 0000000..33ad644 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0510.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAOL7IULalT2Izo9TgRf1t2HNpZ5WCZJH5oRCd9LK3BN
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520 new file mode 100644 index 0000000..630316c --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBlWknnYT5Jdh68dZzjik9hOdgA7AXm2sMLPOzTdfj+ngAAAIghEm1OIRJt +TgAAAAtzc2gtZWQyNTUxOQAAACBlWknnYT5Jdh68dZzjik9hOdgA7AXm2sMLPOzTdfj+ng +AAAEDfVYURudvfzK3ZFx6T2O1CWi0emOZ0MYPcDzUVlu1WmGVaSedhPkl2Hrx1nOOKT2E5 +2ADsBebawws87NN1+P6eAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520-cert.pub new file mode 100644 index 0000000..b290943 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAID/r9T2Sv0NGmlcHl6Fw8rVPIupmsqwq3WAG1NvW7WRcAAAAIGVaSedhPkl2Hrx1nOOKT2E52ADsBebawws87NN1+P6eAAAAAAAAAggAAAABAAAAC3Jldm9rZWQgNTIwAAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABAF8zkeAqwtlxF4iy4mDEHkzVaRqcS0sZ57gcZBWGn/peGFy3MpSxlFQM/IC2pNZ7GuCVSIPV6rRLJC65YMMOEDQ== ./tst-keys/revoked-0520.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520.pub new file mode 100644 index 0000000..fc13d37 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0520.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGVaSedhPkl2Hrx1nOOKT2E52ADsBebawws87NN1+P6e
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550 new file mode 100644 index 0000000..5e671b4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAscmsY+6UVQ3of4MSXpvQS4aFEChpylx3w6wfxrQtSgQAAAIj/9GKZ//Ri +mQAAAAtzc2gtZWQyNTUxOQAAACAscmsY+6UVQ3of4MSXpvQS4aFEChpylx3w6wfxrQtSgQ +AAAEDKC3eEgvCMy86rktq7VU1YQjjKY1iDFPVxWgKKcGJKkyxyaxj7pRVDeh/gxJem9BLh +oUQKGnKXHfDrB/GtC1KBAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550-cert.pub new file mode 100644 index 0000000..f529a91 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIF9q+Cg+9DSKt09eW1NXqVC4dZ3v80sZIYtc0/yqHRb+AAAAICxyaxj7pRVDeh/gxJem9BLhoUQKGnKXHfDrB/GtC1KBAAAAAAAAAiYAAAABAAAAC3Jldm9rZWQgNTUwAAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABAovTuFOXLNCc4hQcI2hatXe2hbBQYbcnUo2BNdJ9EvIOsH/T0DzzEfRQajMQ+QD6oujIx7fb1Z2sRVPOAb3AcBg== ./tst-keys/revoked-0550.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550.pub new file mode 100644 index 0000000..e09316a --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0550.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxyaxj7pRVDeh/gxJem9BLhoUQKGnKXHfDrB/GtC1KB
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799 new file mode 100644 index 0000000..8edd736 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACA/ehirY+MDfjsL60LID9+30FVF04QjC+/eqqhTS1QwgAAAAIjdntzR3Z7c +0QAAAAtzc2gtZWQyNTUxOQAAACA/ehirY+MDfjsL60LID9+30FVF04QjC+/eqqhTS1QwgA +AAAEDQEb+IFCIz+yvkhmrOQ85GafOm9ra0oNRontpox62UTj96GKtj4wN+OwvrQsgP37fQ +VUXThCML796qqFNLVDCAAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799-cert.pub new file mode 100644 index 0000000..80312fb --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIC1z1LkrZhMz1mBWPU8sJIuH59v+ig4OK/B4/x8jLAtUAAAAID96GKtj4wN+OwvrQsgP37fQVUXThCML796qqFNLVDCAAAAAAAAAAx8AAAABAAAAC3Jldm9rZWQgNzk5AAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABASNkJSbdRDARfgbqPOnuES0o6m6VZ7RC2XLPm3uwTqCvMqtHbFvq9etMddSUIR4XXah6ef+O7CJDk/Yjpkn+2CA== ./tst-keys/revoked-0799.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799.pub new file mode 100644 index 0000000..1f0556c --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0799.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID96GKtj4wN+OwvrQsgP37fQVUXThCML796qqFNLVDCA
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999 new file mode 100644 index 0000000..f05a1e4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBIdwRXE815oNRYuS71olA1jkbB81YVApvHpKxCRuvugAAAAIgzBpObMwaT +mwAAAAtzc2gtZWQyNTUxOQAAACBIdwRXE815oNRYuS71olA1jkbB81YVApvHpKxCRuvugA +AAAECxY5wx3XKIhMT+ajMZXPl51x8rkCPBq6gUgZV3Uqpu7Eh3BFcTzXmg1Fi5LvWiUDWO +RsHzVhUCm8ekrEJG6+6AAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999-cert.pub new file mode 100644 index 0000000..4aedb77 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIGt3nV/XJmtz9sQGP2fiZiKOH7mkPhezN3S+8TnsVcQjAAAAIEh3BFcTzXmg1Fi5LvWiUDWORsHzVhUCm8ekrEJG6+6AAAAAAAAAA+cAAAABAAAAC3Jldm9rZWQgOTk5AAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABAvLVCRCs7CV0JSXYL8ge4iRxL4y48bYuvu3YimKZDg7NdCXqw/jkaCsxJykRzb/xVnQDoNVCQQuzydt/I13FdBA== ./tst-keys/revoked-0999.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999.pub new file mode 100644 index 0000000..c837fe0 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-0999.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEh3BFcTzXmg1Fi5LvWiUDWORsHzVhUCm8ekrEJG6+6A
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca new file mode 100644 index 0000000..47e01fb --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAIgok4I2KJOC +NgAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzg +AAAEAEN+knz2qOyj+jbY+SJSHYQhlJoB1u9jLqoQoiAerI3hbReZevLKczhayKUADRdAvZ +5DXVzAJpQkcB4MPdQu/OAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca.pub new file mode 100644 index 0000000..2b92f89 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/O
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca2 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca2 new file mode 100644 index 0000000..770ceee --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca2
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDsEBCX5jBwggkpt4XZXct1fOhDBuvgLL0KMpGoHRtj9wAAAIjMEwOtzBMD +rQAAAAtzc2gtZWQyNTUxOQAAACDsEBCX5jBwggkpt4XZXct1fOhDBuvgLL0KMpGoHRtj9w +AAAEAurE2/d7VhoEJeNFdDnVS7lpBRoMe/zAjA8dJRP1Z/I+wQEJfmMHCCCSm3hdldy3V8 +6EMG6+AsvQoykagdG2P3AAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca2.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca2.pub new file mode 100644 index 0000000..a177fd0 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-ca2.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOwQEJfmMHCCCSm3hdldy3V86EMG6+AsvQoykagdG2P3
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-hash b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-hash new file mode 100644 index 0000000..c6f2361 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-hash
@@ -0,0 +1,11 @@ +hash: SHA256:RvNFBEc/N9jsm3toDkitgr/wnWu/6qWBHo4Xmh5ZUpM +hash: SHA256:qu2IwCnItWWX+orXv0rjCeT4i++2O6ViTzLye6kyWzU +hash: SHA256:qQTACAkAJxYk1zvSQ+Rx9wa2IuOFJKtaEy/XwxM89J0 +hash: SHA256:Fe4GdmipzulS9oMB/h3U69tSm5wil6bTUKSJCT+Jf3E +hash: SHA256:esUK/whZ5oJeRFNeOrHK1bbx9dKC+nRITZ7up7HJaGA +hash: SHA256:xkii+r6t9rEBFYkx1b3dGNXzEs69M5NUMfHP05ypSdI +hash: SHA256:lZrSycKcBNvUafU9y4R0EEbDaQWqMFvIGM9M+VKt2zk +hash: SHA256:/2bgZOiYEH2UVahUllNaQ5P0advEB7liCPkp+aNVKDk +hash: SHA256:He3c0W5o/P1I0pK5/VusqD5V6duAMeZl6f+6Yy5P1z0 +hash: SHA256:5V5Xw2lgcAGR8dO9cbgRmCNlhcCsBBv/hmEstKsqKr4 +hash: SHA256:T7s26JPzzRP2WHOcw3OjLwWo8ZZTkfo2jBCrRfJ6BR4
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-keyid b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-keyid new file mode 100644 index 0000000..592ddb4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-keyid
@@ -0,0 +1,512 @@ +id: revoked 1 +id: revoked 2 +id: revoked 3 +id: revoked 4 +id: revoked 10 +id: revoked 15 +id: revoked 30 +id: revoked 50 +id: revoked 90 +id: revoked 300 +id: revoked 301 +id: revoked 302 +id: revoked 303 +id: revoked 304 +id: revoked 305 +id: revoked 306 +id: revoked 307 +id: revoked 308 +id: revoked 309 +id: revoked 310 +id: revoked 311 +id: revoked 312 +id: revoked 313 +id: revoked 314 +id: revoked 315 +id: revoked 316 +id: revoked 317 +id: revoked 318 +id: revoked 319 +id: revoked 320 +id: revoked 321 +id: revoked 322 +id: revoked 323 +id: revoked 324 +id: revoked 325 +id: revoked 326 +id: revoked 327 +id: revoked 328 +id: revoked 329 +id: revoked 330 +id: revoked 331 +id: revoked 332 +id: revoked 333 +id: revoked 334 +id: revoked 335 +id: revoked 336 +id: revoked 337 +id: revoked 338 +id: revoked 339 +id: revoked 340 +id: revoked 341 +id: revoked 342 +id: revoked 343 +id: revoked 344 +id: revoked 345 +id: revoked 346 +id: revoked 347 +id: revoked 348 +id: revoked 349 +id: revoked 350 +id: revoked 351 +id: revoked 352 +id: revoked 353 +id: revoked 354 +id: revoked 355 +id: revoked 356 +id: revoked 357 +id: revoked 358 +id: revoked 359 +id: revoked 360 +id: revoked 361 +id: revoked 362 +id: revoked 363 +id: revoked 364 +id: revoked 365 +id: revoked 366 +id: revoked 367 +id: revoked 368 +id: revoked 369 +id: revoked 370 +id: revoked 371 +id: revoked 372 +id: revoked 373 +id: revoked 374 +id: revoked 375 +id: revoked 376 +id: revoked 377 +id: revoked 378 +id: revoked 379 +id: revoked 380 +id: revoked 381 +id: revoked 382 +id: revoked 383 +id: revoked 384 +id: revoked 385 +id: revoked 386 +id: revoked 387 +id: revoked 388 +id: revoked 389 +id: revoked 390 +id: revoked 391 +id: revoked 392 +id: revoked 393 +id: revoked 394 +id: revoked 395 +id: revoked 396 +id: revoked 397 +id: revoked 398 +id: revoked 399 +id: revoked 400 +id: revoked 401 +id: revoked 402 +id: revoked 403 +id: revoked 404 +id: revoked 405 +id: revoked 406 +id: revoked 407 +id: revoked 408 +id: revoked 409 +id: revoked 410 +id: revoked 411 +id: revoked 412 +id: revoked 413 +id: revoked 414 +id: revoked 415 +id: revoked 416 +id: revoked 417 +id: revoked 418 +id: revoked 419 +id: revoked 420 +id: revoked 421 +id: revoked 422 +id: revoked 423 +id: revoked 424 +id: revoked 425 +id: revoked 426 +id: revoked 427 +id: revoked 428 +id: revoked 429 +id: revoked 430 +id: revoked 431 +id: revoked 432 +id: revoked 433 +id: revoked 434 +id: revoked 435 +id: revoked 436 +id: revoked 437 +id: revoked 438 +id: revoked 439 +id: revoked 440 +id: revoked 441 +id: revoked 442 +id: revoked 443 +id: revoked 444 +id: revoked 445 +id: revoked 446 +id: revoked 447 +id: revoked 448 +id: revoked 449 +id: revoked 450 +id: revoked 451 +id: revoked 452 +id: revoked 453 +id: revoked 454 +id: revoked 455 +id: revoked 456 +id: revoked 457 +id: revoked 458 +id: revoked 459 +id: revoked 460 +id: revoked 461 +id: revoked 462 +id: revoked 463 +id: revoked 464 +id: revoked 465 +id: revoked 466 +id: revoked 467 +id: revoked 468 +id: revoked 469 +id: revoked 470 +id: revoked 471 +id: revoked 472 +id: revoked 473 +id: revoked 474 +id: revoked 475 +id: revoked 476 +id: revoked 477 +id: revoked 478 +id: revoked 479 +id: revoked 480 +id: revoked 481 +id: revoked 482 +id: revoked 483 +id: revoked 484 +id: revoked 485 +id: revoked 486 +id: revoked 487 +id: revoked 488 +id: revoked 489 +id: revoked 490 +id: revoked 491 +id: revoked 492 +id: revoked 493 +id: revoked 494 +id: revoked 495 +id: revoked 496 +id: revoked 497 +id: revoked 498 +id: revoked 500 +id: revoked 501 +id: revoked 502 +id: revoked 503 +id: revoked 504 +id: revoked 505 +id: revoked 506 +id: revoked 507 +id: revoked 508 +id: revoked 509 +id: revoked 510 +id: revoked 511 +id: revoked 512 +id: revoked 513 +id: revoked 514 +id: revoked 515 +id: revoked 516 +id: revoked 517 +id: revoked 518 +id: revoked 519 +id: revoked 520 +id: revoked 521 +id: revoked 522 +id: revoked 523 +id: revoked 524 +id: revoked 525 +id: revoked 526 +id: revoked 527 +id: revoked 528 +id: revoked 529 +id: revoked 530 +id: revoked 531 +id: revoked 532 +id: revoked 533 +id: revoked 534 +id: revoked 535 +id: revoked 536 +id: revoked 537 +id: revoked 538 +id: revoked 539 +id: revoked 540 +id: revoked 541 +id: revoked 542 +id: revoked 543 +id: revoked 544 +id: revoked 545 +id: revoked 546 +id: revoked 547 +id: revoked 548 +id: revoked 549 +id: revoked 550 +id: revoked 551 +id: revoked 552 +id: revoked 553 +id: revoked 554 +id: revoked 555 +id: revoked 556 +id: revoked 557 +id: revoked 558 +id: revoked 559 +id: revoked 560 +id: revoked 561 +id: revoked 562 +id: revoked 563 +id: revoked 564 +id: revoked 565 +id: revoked 566 +id: revoked 567 +id: revoked 568 +id: revoked 569 +id: revoked 570 +id: revoked 571 +id: revoked 572 +id: revoked 573 +id: revoked 574 +id: revoked 575 +id: revoked 576 +id: revoked 577 +id: revoked 578 +id: revoked 579 +id: revoked 580 +id: revoked 581 +id: revoked 582 +id: revoked 583 +id: revoked 584 +id: revoked 585 +id: revoked 586 +id: revoked 587 +id: revoked 588 +id: revoked 589 +id: revoked 590 +id: revoked 591 +id: revoked 592 +id: revoked 593 +id: revoked 594 +id: revoked 595 +id: revoked 596 +id: revoked 597 +id: revoked 598 +id: revoked 599 +id: revoked 600 +id: revoked 601 +id: revoked 602 +id: revoked 603 +id: revoked 604 +id: revoked 605 +id: revoked 606 +id: revoked 607 +id: revoked 608 +id: revoked 609 +id: revoked 610 +id: revoked 611 +id: revoked 612 +id: revoked 613 +id: revoked 614 +id: revoked 615 +id: revoked 616 +id: revoked 617 +id: revoked 618 +id: revoked 619 +id: revoked 620 +id: revoked 621 +id: revoked 622 +id: revoked 623 +id: revoked 624 +id: revoked 625 +id: revoked 626 +id: revoked 627 +id: revoked 628 +id: revoked 629 +id: revoked 630 +id: revoked 631 +id: revoked 632 +id: revoked 633 +id: revoked 634 +id: revoked 635 +id: revoked 636 +id: revoked 637 +id: revoked 638 +id: revoked 639 +id: revoked 640 +id: revoked 641 +id: revoked 642 +id: revoked 643 +id: revoked 644 +id: revoked 645 +id: revoked 646 +id: revoked 647 +id: revoked 648 +id: revoked 649 +id: revoked 650 +id: revoked 651 +id: revoked 652 +id: revoked 653 +id: revoked 654 +id: revoked 655 +id: revoked 656 +id: revoked 657 +id: revoked 658 +id: revoked 659 +id: revoked 660 +id: revoked 661 +id: revoked 662 +id: revoked 663 +id: revoked 664 +id: revoked 665 +id: revoked 666 +id: revoked 667 +id: revoked 668 +id: revoked 669 +id: revoked 670 +id: revoked 671 +id: revoked 672 +id: revoked 673 +id: revoked 674 +id: revoked 675 +id: revoked 676 +id: revoked 677 +id: revoked 678 +id: revoked 679 +id: revoked 680 +id: revoked 681 +id: revoked 682 +id: revoked 683 +id: revoked 684 +id: revoked 685 +id: revoked 686 +id: revoked 687 +id: revoked 688 +id: revoked 689 +id: revoked 690 +id: revoked 691 +id: revoked 692 +id: revoked 693 +id: revoked 694 +id: revoked 695 +id: revoked 696 +id: revoked 697 +id: revoked 698 +id: revoked 699 +id: revoked 700 +id: revoked 701 +id: revoked 702 +id: revoked 703 +id: revoked 704 +id: revoked 705 +id: revoked 706 +id: revoked 707 +id: revoked 708 +id: revoked 709 +id: revoked 710 +id: revoked 711 +id: revoked 712 +id: revoked 713 +id: revoked 714 +id: revoked 715 +id: revoked 716 +id: revoked 717 +id: revoked 718 +id: revoked 719 +id: revoked 720 +id: revoked 721 +id: revoked 722 +id: revoked 723 +id: revoked 724 +id: revoked 725 +id: revoked 726 +id: revoked 727 +id: revoked 728 +id: revoked 729 +id: revoked 730 +id: revoked 731 +id: revoked 732 +id: revoked 733 +id: revoked 734 +id: revoked 735 +id: revoked 736 +id: revoked 737 +id: revoked 738 +id: revoked 739 +id: revoked 740 +id: revoked 741 +id: revoked 742 +id: revoked 743 +id: revoked 744 +id: revoked 745 +id: revoked 746 +id: revoked 747 +id: revoked 748 +id: revoked 749 +id: revoked 750 +id: revoked 751 +id: revoked 752 +id: revoked 753 +id: revoked 754 +id: revoked 755 +id: revoked 756 +id: revoked 757 +id: revoked 758 +id: revoked 759 +id: revoked 760 +id: revoked 761 +id: revoked 762 +id: revoked 763 +id: revoked 764 +id: revoked 765 +id: revoked 766 +id: revoked 767 +id: revoked 768 +id: revoked 769 +id: revoked 770 +id: revoked 771 +id: revoked 772 +id: revoked 773 +id: revoked 774 +id: revoked 775 +id: revoked 776 +id: revoked 777 +id: revoked 778 +id: revoked 779 +id: revoked 780 +id: revoked 781 +id: revoked 782 +id: revoked 783 +id: revoked 784 +id: revoked 785 +id: revoked 786 +id: revoked 787 +id: revoked 788 +id: revoked 789 +id: revoked 790 +id: revoked 791 +id: revoked 792 +id: revoked 793 +id: revoked 794 +id: revoked 795 +id: revoked 796 +id: revoked 797 +id: revoked 798 +id: revoked 799 +id: revoked 999 +id: revoked 1000 +id: revoked 1001 +id: revoked 1002
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-serials b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-serials new file mode 100644 index 0000000..b20fec2 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-serials
@@ -0,0 +1,19 @@ +serial: 1-4 +serial: 10 +serial: 15 +serial: 30 +serial: 50 +serial: 90 +serial: 999 +# The following sum to 500-799 +serial: 500 +serial: 501 +serial: 502 +serial: 503-600 +serial: 700-797 +serial: 798 +serial: 799 +serial: 599-701 +# Some multiple consecutive serial number ranges +serial: 10000-20000 +serial: 30000-40000
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-sha1 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-sha1 new file mode 100644 index 0000000..475e90c --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-sha1
@@ -0,0 +1,11 @@ +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC29QZ72HtyCdaNo6p2GH3fJpUynwkvs8Acwn66G7YTh +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0ZC4fqgbBgROeX1sOEPr4uMVNfPdJ62bVo/zvSMRQx +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG5IH9T7FY47VJDUoyOlB/iqCN4pO8dgOrxclmKN5R5w +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINjhG4+EnQy8YHLsfE8+IQwNWZVn1GBYX75pwxBCZGmy +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXm+qgTs+sO+9zvoZBxkQD39R2rQqQCVezxQoGjKui5 +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL8+aQKja+SbqxfWR61FCcsbBw2jaF/KHvcqdP2Fbp6Q +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAOL7IULalT2Izo9TgRf1t2HNpZ5WCZJH5oRCd9LK3BN +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGVaSedhPkl2Hrx1nOOKT2E52ADsBebawws87NN1+P6e +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxyaxj7pRVDeh/gxJem9BLhoUQKGnKXHfDrB/GtC1KB +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID96GKtj4wN+OwvrQsgP37fQVUXThCML796qqFNLVDCA +sha1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEh3BFcTzXmg1Fi5LvWiUDWORsHzVhUCm8ekrEJG6+6A
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-sha256 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-sha256 new file mode 100644 index 0000000..13109e9 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/revoked-sha256
@@ -0,0 +1,11 @@ +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC29QZ72HtyCdaNo6p2GH3fJpUynwkvs8Acwn66G7YTh +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0ZC4fqgbBgROeX1sOEPr4uMVNfPdJ62bVo/zvSMRQx +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG5IH9T7FY47VJDUoyOlB/iqCN4pO8dgOrxclmKN5R5w +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINjhG4+EnQy8YHLsfE8+IQwNWZVn1GBYX75pwxBCZGmy +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXm+qgTs+sO+9zvoZBxkQD39R2rQqQCVezxQoGjKui5 +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL8+aQKja+SbqxfWR61FCcsbBw2jaF/KHvcqdP2Fbp6Q +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAOL7IULalT2Izo9TgRf1t2HNpZ5WCZJH5oRCd9LK3BN +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGVaSedhPkl2Hrx1nOOKT2E52ADsBebawws87NN1+P6e +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxyaxj7pRVDeh/gxJem9BLhoUQKGnKXHfDrB/GtC1KB +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID96GKtj4wN+OwvrQsgP37fQVUXThCML796qqFNLVDCA +sha256: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEh3BFcTzXmg1Fi5LvWiUDWORsHzVhUCm8ekrEJG6+6A
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005 new file mode 100644 index 0000000..d82a0b5 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDqONQediveIXoseoT+MWp9yEdMO7hP7F4fAno6gunyoAAAAIig1MZroNTG +awAAAAtzc2gtZWQyNTUxOQAAACDqONQediveIXoseoT+MWp9yEdMO7hP7F4fAno6gunyoA +AAAEBSEPLoX4NVkAchYZEGi7hjd5NoVBWuoxqluCGt/fWrYeo41B52K94heix6hP4xan3I +R0w7uE/sXh8CejqC6fKgAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005-cert.pub new file mode 100644 index 0000000..59ea422 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIGnzDhP/hp83ipkW8T7f0CIXJuPK7ldbJFKDUrkvn6J1AAAAIOo41B52K94heix6hP4xan3IR0w7uE/sXh8CejqC6fKgAAAAAAAAAAUAAAABAAAACXJldm9rZWQgNQAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgFtF5l68spzOFrIpQANF0C9nkNdXMAmlCRwHgw91C784AAABTAAAAC3NzaC1lZDI1NTE5AAAAQO9W58IrK+I0o2us9Hs/QBkrEe1YIgl6PzCMsu/Zu/tdZxGDK5Pxoz7tKzXezS9LPGQfZ3fVdl58PZC1DtxQ5gU= ./tst-keys/unrevoked-0005.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005.pub new file mode 100644 index 0000000..081ac6c --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0005.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOo41B52K94heix6hP4xan3IR0w7uE/sXh8CejqC6fKg
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009 new file mode 100644 index 0000000..9479498 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDXQqTeALQCMo64B4EX5abjRvrjVu69Mnxgg2q0SB5/oQAAAIgIqeXLCKnl +ywAAAAtzc2gtZWQyNTUxOQAAACDXQqTeALQCMo64B4EX5abjRvrjVu69Mnxgg2q0SB5/oQ +AAAECubGChJGu90ZNiP/zF+tTtr0+l7y8BrTDMQ0m0+cU0qtdCpN4AtAIyjrgHgRflpuNG ++uNW7r0yfGCDarRIHn+hAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009-cert.pub new file mode 100644 index 0000000..9ee8890 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIERRY0M1bHm2Qjyo105OCHWp0UCRHLP0xkMuHnkMDP5eAAAAINdCpN4AtAIyjrgHgRflpuNG+uNW7r0yfGCDarRIHn+hAAAAAAAAAAkAAAABAAAACXJldm9rZWQgOQAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgFtF5l68spzOFrIpQANF0C9nkNdXMAmlCRwHgw91C784AAABTAAAAC3NzaC1lZDI1NTE5AAAAQFsA4xJHRCXSyq6GHkKdemfbg+jvUZxHlu/UBoZf4esEHAtx0mXiajbUwkWzkh1vCtxZNZhiLIhxqDcNMu+O+wo= ./tst-keys/unrevoked-0009.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009.pub new file mode 100644 index 0000000..74a797b --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0009.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINdCpN4AtAIyjrgHgRflpuNG+uNW7r0yfGCDarRIHn+h
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014 new file mode 100644 index 0000000..6fa4fd9 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDvTTMHyjozzZabuUzy61XOKBm4klUjUGSWYtX6T4XtEwAAAIhyFdxYchXc +WAAAAAtzc2gtZWQyNTUxOQAAACDvTTMHyjozzZabuUzy61XOKBm4klUjUGSWYtX6T4XtEw +AAAEBtC+f4bz1/qtq5K2Rf+0bPeY3P0OWdD3rvrlGPh8wN5u9NMwfKOjPNlpu5TPLrVc4o +GbiSVSNQZJZi1fpPhe0TAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014-cert.pub new file mode 100644 index 0000000..bb954f9 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIPes2n/Xk4mm4OpuvHDqx9+76vm+SmFgc9d7ATGT1+C8AAAAIO9NMwfKOjPNlpu5TPLrVc4oGbiSVSNQZJZi1fpPhe0TAAAAAAAAAA4AAAABAAAACnJldm9rZWQgMTQAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEDGVORypw3DoMuWBu0V4cH/OgRBstD5cY37CfLrVZpmGv9jDRXVNQee7vYowk0r3XvQPoUecQBIMZGAQtEiw18E ./tst-keys/unrevoked-0014.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014.pub new file mode 100644 index 0000000..4a866e4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0014.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO9NMwfKOjPNlpu5TPLrVc4oGbiSVSNQZJZi1fpPhe0T
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016 new file mode 100644 index 0000000..62d5027 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBWKMDlSwSGo4dcBAZmL+Xxk64Wp/ZfFSu2vkp82JXQCQAAAIjUcNt51HDb +eQAAAAtzc2gtZWQyNTUxOQAAACBWKMDlSwSGo4dcBAZmL+Xxk64Wp/ZfFSu2vkp82JXQCQ +AAAEC1V7PD5tJSOUZtpfqVfWyiSIMJkCDFZzTmFs7GBpJE71YowOVLBIajh1wEBmYv5fGT +rhan9l8VK7a+SnzYldAJAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016-cert.pub new file mode 100644 index 0000000..367e4ab --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAICGqa0xwr0etbKquuBy5/hYQ/rbMrKfEE6XShgb4YWpUAAAAIFYowOVLBIajh1wEBmYv5fGTrhan9l8VK7a+SnzYldAJAAAAAAAAABAAAAABAAAACnJldm9rZWQgMTYAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEBKVetE3dsch2wjMIHGoiH8zp6gFMn1KgGKn01EPc1A08a/JKNvaSDYhlARLjiBzjIUGlykhHTTr4EcHTPWl58P ./tst-keys/unrevoked-0016.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016.pub new file mode 100644 index 0000000..47cac1e --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0016.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFYowOVLBIajh1wEBmYv5fGTrhan9l8VK7a+SnzYldAJ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029 new file mode 100644 index 0000000..589daa6 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACA3B1NQ9RFEkJUGcIUcCL22yMVEeob8/PUsk9lYH43vPwAAAIjxPrzV8T68 +1QAAAAtzc2gtZWQyNTUxOQAAACA3B1NQ9RFEkJUGcIUcCL22yMVEeob8/PUsk9lYH43vPw +AAAED89ht9KdlYRfsKwh+pzh6BOvPf/U58QBkw1d3LfKnn+jcHU1D1EUSQlQZwhRwIvbbI +xUR6hvz89SyT2Vgfje8/AAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029-cert.pub new file mode 100644 index 0000000..1bf3883 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIEVLRuchC4z7/EqITmyqCxOyhC7/enmFWsalP8FFFYiXAAAAIDcHU1D1EUSQlQZwhRwIvbbIxUR6hvz89SyT2Vgfje8/AAAAAAAAAB0AAAABAAAACnJldm9rZWQgMjkAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEChRFz/Zb6b3znoIWJjd8OTmCIEH7YE/fKWtyWHoGjz02G4VnCfwuHp23yD+k1XsoOGC7xcSnQeqZ19160HDNgC ./tst-keys/unrevoked-0029.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029.pub new file mode 100644 index 0000000..4072d92 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0029.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDcHU1D1EUSQlQZwhRwIvbbIxUR6hvz89SyT2Vgfje8/
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049 new file mode 100644 index 0000000..b5788a0 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACD2mB5GBuavtb/bX7W54OmUCCJzUWBwG7cQ4q/jon1MBQAAAIjRkEU40ZBF +OAAAAAtzc2gtZWQyNTUxOQAAACD2mB5GBuavtb/bX7W54OmUCCJzUWBwG7cQ4q/jon1MBQ +AAAECuUtJb+T0um2mGvjD/ZZpbtjIhWc3jGVbzuDnEovOjnPaYHkYG5q+1v9tftbng6ZQI +InNRYHAbtxDir+OifUwFAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049-cert.pub new file mode 100644 index 0000000..587cf62 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAILZPLEL5xQ8HDLa8pJhchJ3EEhZcjMqACCAEeL+U6c/QAAAAIPaYHkYG5q+1v9tftbng6ZQIInNRYHAbtxDir+OifUwFAAAAAAAAADEAAAABAAAACnJldm9rZWQgNDkAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB2GglzoC1VgsYNAVd5BDsLbeR5M5hHcVVvNsGnK1QCXMj56cgfkbXLj6W6tjJEEFY4G+KPJh1F/SGJi02P5lkJ ./tst-keys/unrevoked-0049.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049.pub new file mode 100644 index 0000000..07d5369 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0049.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPaYHkYG5q+1v9tftbng6ZQIInNRYHAbtxDir+OifUwF
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051 new file mode 100644 index 0000000..52d3283 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACD39ygfAlHPhZWU8inWu1hypIlQTChQxSKKB6iaV6Q0lQAAAIgMawsqDGsL +KgAAAAtzc2gtZWQyNTUxOQAAACD39ygfAlHPhZWU8inWu1hypIlQTChQxSKKB6iaV6Q0lQ +AAAEB4Ng9MekhsMKYDaBcOUWdxmi1rjgCsPOOfpABTxiCef/f3KB8CUc+FlZTyKda7WHKk +iVBMKFDFIooHqJpXpDSVAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051-cert.pub new file mode 100644 index 0000000..5b4bd11 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIGTNYRrlJ1vExK7dume319Krn4YW6wyZc4PzZLjZoB8zAAAAIPf3KB8CUc+FlZTyKda7WHKkiVBMKFDFIooHqJpXpDSVAAAAAAAAADMAAAABAAAACnJldm9rZWQgNTEAAAAAAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBbReZevLKczhayKUADRdAvZ5DXVzAJpQkcB4MPdQu/OAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEAgUiwWKerMo8nuejTER/EmM6ZUpmXjgFwPCpb1LAxBJH71iOnyF9S0gp+CSmjqiTS2yuQajSMen64wOdJCX7wF ./tst-keys/unrevoked-0051.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051.pub new file mode 100644 index 0000000..88867e5 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0051.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPf3KB8CUc+FlZTyKda7WHKkiVBMKFDFIooHqJpXpDSV
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499 new file mode 100644 index 0000000..8f59be9 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCpwI1aCbAOVvA7NJhLtBNpR4tiGGtTQ019wjKL6zJ/uQAAAIhllrzrZZa8 +6wAAAAtzc2gtZWQyNTUxOQAAACCpwI1aCbAOVvA7NJhLtBNpR4tiGGtTQ019wjKL6zJ/uQ +AAAECQ6o+3J9W3wXFWEcrPJl5qJZudUPmPdKF7SYxcMTrVP6nAjVoJsA5W8Ds0mEu0E2lH +i2IYa1NDTX3CMovrMn+5AAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499-cert.pub new file mode 100644 index 0000000..a6e76f1 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJvt1IxZsGIIS9DDCCKiD13Dbs5Af5ouews+YwZ9FoydAAAAIKnAjVoJsA5W8Ds0mEu0E2lHi2IYa1NDTX3CMovrMn+5AAAAAAAAAfMAAAABAAAAC3Jldm9rZWQgNDk5AAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABAMaA4UjND4LX9kdHjhgWJjGzzs/xUBwxQQcAmNgwmmQzmkwj8ctWBBA1+TkBMcZbSNUWBdclT4UcnDPEYqG1NBg== ./tst-keys/unrevoked-0499.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499.pub new file mode 100644 index 0000000..5a3acbb --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0499.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKnAjVoJsA5W8Ds0mEu0E2lHi2IYa1NDTX3CMovrMn+5
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800 new file mode 100644 index 0000000..9684d72 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAn5h8A2vYJ1+IWVtdLMulUQKCqlVLHpcHEFqYC5gtGlwAAAIh2lf7UdpX+ +1AAAAAtzc2gtZWQyNTUxOQAAACAn5h8A2vYJ1+IWVtdLMulUQKCqlVLHpcHEFqYC5gtGlw +AAAEAEXGgMPKs3HwkQmNdVkbO3PcaBVCBEv1l8yy/ly30jPSfmHwDa9gnX4hZW10sy6VRA +oKqVUselwcQWpgLmC0aXAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800-cert.pub new file mode 100644 index 0000000..ab47a2b --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIPAKFTJ25v9CsCppsQ/FwXAZgntAIdQHUXo0KQ3FrlTzAAAAICfmHwDa9gnX4hZW10sy6VRAoKqVUselwcQWpgLmC0aXAAAAAAAAAyAAAAABAAAAC3Jldm9rZWQgODAwAAAAAAAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAW0XmXryynM4WsilAA0XQL2eQ11cwCaUJHAeDD3ULvzgAAAFMAAAALc3NoLWVkMjU1MTkAAABA16aKfsgD0iZ+qc2b1AxBHZ/nyczN2Xjbhg4eJm/6cPSkBHs8uan5e8yPBIQJq2LztC3If6Z6PARoWUnIKb43CQ== ./tst-keys/unrevoked-0800.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800.pub new file mode 100644 index 0000000..3a41f29 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-0800.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICfmHwDa9gnX4hZW10sy6VRAoKqVUselwcQWpgLmC0aX
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010 new file mode 100644 index 0000000..89df717 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAg0jawQzRMO/ESfFm6yDc66J5kjasOqTb7rmQSU6Nk3QAAAIhczXMoXM1z +KAAAAAtzc2gtZWQyNTUxOQAAACAg0jawQzRMO/ESfFm6yDc66J5kjasOqTb7rmQSU6Nk3Q +AAAEAdeQiqpyZqBaffmgy+UrvFVpygD0n8isn3zjumVNtKxiDSNrBDNEw78RJ8WbrINzro +nmSNqw6pNvuuZBJTo2TdAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010-cert.pub new file mode 100644 index 0000000..2d0fe53 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIITg9nSjjofIKXTKf2byvYL3Ce43PP9Dtrbj/+AlfgEtAAAAICDSNrBDNEw78RJ8WbrINzronmSNqw6pNvuuZBJTo2TdAAAAAAAAA/IAAAABAAAADHJldm9rZWQgMTAxMAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgFtF5l68spzOFrIpQANF0C9nkNdXMAmlCRwHgw91C784AAABTAAAAC3NzaC1lZDI1NTE5AAAAQIndHhKILtU0+FkKKw1KmhaHQS3p1KiQdld/2P5jpcEgb292iY+ICU+aHXKvS8qGM2aMImv8835NEyWy/MB74QM= ./tst-keys/unrevoked-1010.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010.pub new file mode 100644 index 0000000..05c5eac --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1010.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICDSNrBDNEw78RJ8WbrINzronmSNqw6pNvuuZBJTo2Td
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011 b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011 new file mode 100644 index 0000000..38b8232 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCd4IBQx9BhO9FzYMOKu3cKgBcwUwb7XzS3uI26RgmEYgAAAIjHvhtux74b +bgAAAAtzc2gtZWQyNTUxOQAAACCd4IBQx9BhO9FzYMOKu3cKgBcwUwb7XzS3uI26RgmEYg +AAAEBsteyDUYUNwgY3SMkMs0guy8MJfek2kuvH35zEpVf6Hp3ggFDH0GE70XNgw4q7dwqA +FzBTBvtfNLe4jbpGCYRiAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011-cert.pub new file mode 100644 index 0000000..4671638 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMjD2+xjmUC1VviOH+peT9C81Y4xjyTue/F69nFKmQBMAAAAIJ3ggFDH0GE70XNgw4q7dwqAFzBTBvtfNLe4jbpGCYRiAAAAAAAAA/MAAAABAAAADHJldm9rZWQgMTAxMQAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgFtF5l68spzOFrIpQANF0C9nkNdXMAmlCRwHgw91C784AAABTAAAAC3NzaC1lZDI1NTE5AAAAQNENdVFCE02X6z+wFJtm2DQcgdc4oov9DyFKLPqLrogo+pVao5QwOkeJ2J/tmp40H2+uP/jrDlQuCvOcoQGHqwY= ./tst-keys/unrevoked-1011.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011.pub new file mode 100644 index 0000000..0809077 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/krl/unrevoked-1011.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ3ggFDH0GE70XNgw4q7dwqAFzBTBvtfNLe4jbpGCYRi
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key new file mode 100644 index 0000000..ee3f922 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACA3ivU7wf37jE1ITC5KQjVeVlyFTkgWJxub8t380ovjiwAAAJDdMhQO3TIU +DgAAAAtzc2gtZWQyNTUxOQAAACA3ivU7wf37jE1ITC5KQjVeVlyFTkgWJxub8t380ovjiw +AAAEA4NlTFs3h2zqt5pSZ5S3dJb42GE7EjG16coKj70eELNDeK9TvB/fuMTUhMLkpCNV5W +XIVOSBYnG5vy3fzSi+OLAAAADVRIV09AU0VBR044MDA= +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key-cert.pub new file mode 100644 index 0000000..2be08be --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIGXo4+L/NyBl1VQDP39PxJP3LSzaqopqZGVP3cG0WoFAAAAAIDeK9TvB/fuMTUhMLkpCNV5WXIVOSBYnG5vy3fzSi+OLAAAAAAAAAAUAAAABAAAABnRlc3RlcgAAABYAAAASdGVzdGVyQGV4YW1wbGUuY29tAAAAAGbTroAAAAAAZyLIgAAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIMdEl+iOTEbf1RC3uicECtid+SaIMsAw7wrlWhOQTyBVAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEA/HwKB8J/kvkEsdxDou+UebnR9u30xPH6FEnbHLlfKbKMIXwLFIHnf9F6bTL36WhFDEDcSBGS19VBWBDRosM8L
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key.pub new file mode 100644 index 0000000..0255005 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/other_key.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDeK9TvB/fuMTUhMLkpCNV5WXIVOSBYnG5vy3fzSi+OL
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/repo.bundle b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/repo.bundle new file mode 100644 index 0000000..c402f54 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/repo.bundle Binary files differ
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key new file mode 100644 index 0000000..3dd37be --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key
@@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBgEzmfD3DinWPe/H8yLLZ2dPhbnnyFiqe8EWcp0C3czgAAAJDhSMqA4UjK +gAAAAAtzc2gtZWQyNTUxOQAAACBgEzmfD3DinWPe/H8yLLZ2dPhbnnyFiqe8EWcp0C3czg +AAAEB1yC00NMYEAVzhDj9odGVL0EonaIkf5jdUZ/czJ0+SPWATOZ8PcOKdY978fzIstnZ0 ++FuefIWKp7wRZynQLdzOAAAADVRIV09AU0VBR044MDA= +-----END OPENSSH PRIVATE KEY-----
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key-cert.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key-cert.pub new file mode 100644 index 0000000..de191d1 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key-cert.pub
@@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIFEmoWkYraMju0JI0b/0RQtR6RYo/OVp53EVf48L/Pu/AAAAIBmHlkHFlA7HkoTZcau80PH5zduQu41m8BqnH/1v2BwVAAAAAAAAAAEAAAABAAAACGFfa2V5X2lkAAAAFgAAABJ0ZXN0ZXJAZXhhbXBsZS5jb20AAAAAZtOugAAAAABm1QAAAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAg2ifM9NMuXwQf7H/H5LCMhMjVqugyyN+jmcMoJUL2YLAAAABTAAAAC3NzaC1lZDI1NTE5AAAAQG1kXUido46YOnmwvkJuIAKyp6Q9Gr+lbdOQvU0St/Hc9HTTIxgDGyLpv0alIJpHOuSYUUUxDufvGKtLJK1duwg= ./signing_key.pub
diff --git a/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key.pub b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key.pub new file mode 100644 index 0000000..e1210e7 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst-rsrc/org/eclipse/jgit/internal/signing/ssh/signing_key.pub
@@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AbstractSshSignatureTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AbstractSshSignatureTest.java new file mode 100644 index 0000000..fdfffce --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AbstractSshSignatureTest.java
@@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.time.Instant; +import java.time.ZoneOffset; + +import org.eclipse.jgit.api.CommitCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; + +/** + * Common setup for SSH signature tests. + */ +public abstract class AbstractSshSignatureTest extends RepositoryTestCase { + + @Rule + public TemporaryFolder keys = new TemporaryFolder(); + + protected File certs; + + protected Instant commitTime; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + copyResource("allowed_signers", keys.getRoot()); + copyResource("other_key", keys.getRoot()); + copyResource("other_key.pub", keys.getRoot()); + copyResource("other_key-cert.pub", keys.getRoot()); + copyResource("signing_key", keys.getRoot()); + copyResource("signing_key.pub", keys.getRoot()); + certs = keys.newFolder("certs"); + copyResource("certs/expired.cert", certs); + copyResource("certs/no_principals.cert", certs); + copyResource("certs/other.cert", certs); + copyResource("certs/other-ca.cert", certs); + copyResource("certs/tester.cert", certs); + copyResource("certs/two_principals.cert", certs); + Repository repo = db; + StoredConfig config = repo.getConfig(); + config.setString("gpg", null, "format", "ssh"); + config.setString("gpg", "ssh", "allowedSignersFile", + keys.getRoot().toPath().resolve("allowed_signers").toString() + .replace('\\', '/')); + config.save(); + // Run all tests with commit times on 2024-10-02T12:00:00Z. The test + // certificates are valid from 2024-09-01 to 2024-10-31, except the + // "expired" certificate which is valid only on 2024-09-01. + commitTime = Instant.parse("2024-10-02T12:00:00.00Z"); + } + + private void copyResource(String name, File directory) throws IOException { + try (InputStream in = this.getClass().getResourceAsStream(name)) { + int i = name.lastIndexOf('/'); + String fileName = i < 0 ? name : name.substring(i + 1); + Files.copy(in, directory.toPath().resolve(fileName)); + } + } + + protected RevCommit createSignedCommit(String certificate, + String signingKey) throws Exception { + Repository repo = db; + Path key = keys.getRoot().toPath().resolve(signingKey); + if (certificate != null) { + Files.copy(certs.toPath().resolve(certificate), + keys.getRoot().toPath().resolve(signingKey), + StandardCopyOption.REPLACE_EXISTING); + } + PersonIdent commitAuthor = new PersonIdent("tester", + "tester@example.com", commitTime, ZoneOffset.UTC); + try (Git git = Git.wrap(repo)) { + writeTrashFile("foo.txt", "foo"); + git.add().addFilepattern("foo.txt").call(); + CommitCommand commit = git.commit(); + commit.setAuthor(commitAuthor); + commit.setCommitter(commitAuthor); + commit.setMessage("Message"); + commit.setSign(Boolean.TRUE); + commit.setSigningKey(key.toAbsolutePath().toString()); + return commit.call(); + } + } + + protected RevCommit checkSshSignature(RevCommit c) { + byte[] sig = c.getRawGpgSignature(); + assertNotNull(sig); + String signature = new String(sig, StandardCharsets.US_ASCII); + assertTrue("Not an SSH signature:\n" + signature, + signature.startsWith(Constants.SSH_SIGNATURE_PREFIX)); + return c; + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AllowedSignersParseTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AllowedSignersParseTest.java new file mode 100644 index 0000000..84d8179 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AllowedSignersParseTest.java
@@ -0,0 +1,211 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; + +import java.io.StreamCorruptedException; +import java.time.Instant; + +import org.eclipse.jgit.junit.MockSystemReader; +import org.eclipse.jgit.util.SystemReader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the line parsing in {@link AllowedSigners}. + */ +public class AllowedSignersParseTest { + + @Before + public void setup() { + // Uses GMT-03:30 as time zone. + SystemReader.setInstance(new MockSystemReader()); + } + + @After + public void tearDown() { + SystemReader.setInstance(null); + } + + @Test + public void testValidDate() { + assertEquals(Instant.parse("2024-09-01T00:00:00.00Z"), + AllowedSigners.parseDate("20240901Z")); + assertEquals(Instant.parse("2024-09-01T01:02:00.00Z"), + AllowedSigners.parseDate("202409010102Z")); + assertEquals(Instant.parse("2024-09-01T01:02:03.00Z"), + AllowedSigners.parseDate("20240901010203Z")); + assertEquals(Instant.parse("2024-09-01T03:30:00.00Z"), + AllowedSigners.parseDate("20240901")); + assertEquals(Instant.parse("2024-09-01T04:32:00.00Z"), + AllowedSigners.parseDate("202409010102")); + assertEquals(Instant.parse("2024-09-01T04:32:03.00Z"), + AllowedSigners.parseDate("20240901010203")); + } + + @Test + public void testInvalidDate() { + assertThrows(Exception.class, () -> AllowedSigners.parseDate("1234")); + assertThrows(Exception.class, + () -> AllowedSigners.parseDate("09/01/2024")); + assertThrows(Exception.class, + () -> AllowedSigners.parseDate("2024-09-01")); + } + + private void checkValidKey(String expected, String input, int from) + throws StreamCorruptedException { + assertEquals(expected, AllowedSigners.parsePublicKey(input, from)); + } + @Test + public void testValidPublicKey() throws StreamCorruptedException { + checkValidKey( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO", + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO", + 0); + checkValidKey( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO", + "xyzssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO", + 3); + checkValidKey( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO", + "xyz ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO abc", + 3); + checkValidKey( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO", + "xyz\tssh-ed25519 \tAAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO abc", + 3); + } + + @Test + public void testInvalidPublicKey() { + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey(null, 0)); + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey("", 0)); + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey("foo", 0)); + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey("ssh-ed25519 bar", -1)); + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey("ssh-ed25519 bar", 12)); + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey("ssh-ed25519 bar", 13)); + assertThrows(Exception.class, + () -> AllowedSigners.parsePublicKey("ssh-ed25519 bar", 16)); + } + + @Test + public void testValidDequote() { + assertEquals(new AllowedSigners.Dequoted("a\\bc", 4), + AllowedSigners.dequote("a\\bc", 0)); + assertEquals(new AllowedSigners.Dequoted("a\\bc\"", 5), + AllowedSigners.dequote("a\\bc\"", 0)); + assertEquals(new AllowedSigners.Dequoted("a\\b\"c", 5), + AllowedSigners.dequote("a\\b\"c", 0)); + assertEquals(new AllowedSigners.Dequoted("a\\b\"c", 8), + AllowedSigners.dequote("\"a\\b\\\"c\"", 0)); + assertEquals(new AllowedSigners.Dequoted("a\\b\"c", 11), + AllowedSigners.dequote("xyz\"a\\b\\\"c\"", 3)); + assertEquals(new AllowedSigners.Dequoted("abc", 6), + AllowedSigners.dequote(" abc def", 3)); + } + + @Test + public void testInvalidDequote() { + assertThrows(Exception.class, () -> AllowedSigners.dequote("\"abc", 0)); + assertThrows(Exception.class, + () -> AllowedSigners.dequote("\"abc\\\"", 0)); + } + + @Test + public void testValidLine() throws Exception { + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "*@a.com" }, + true, null, null, null, + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO"), + AllowedSigners.parseLine( + "*@a.com cert-authority ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "*@a.com", "*@b.a.com" }, + true, null, null, null, + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO"), + AllowedSigners.parseLine( + "*@a.com,*@b.a.com cert-authority ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "foo@a.com" }, + false, null, null, null, + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO"), + AllowedSigners.parseLine( + "foo@a.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "foo@a.com" }, + false, new String[] { "foo", "bar" }, null, null, + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO"), + AllowedSigners.parseLine( + "foo@a.com namespaces=\"foo,bar\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "foo@a.com" }, + false, null, Instant.parse("2024-09-01T03:30:00.00Z"), null, + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO"), + AllowedSigners.parseLine( + "foo@a.com valid-After=\"20240901\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "*@a.com", "*@b.a.com" }, + true, new String[] { "git" }, + Instant.parse("2024-09-01T03:30:00.00Z"), + Instant.parse("2024-09-01T12:00:00.00Z"), + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO"), + AllowedSigners.parseLine( + "*@a.com,*@b.a.com cert-authority namespaces=\"git\" valid-after=\"20240901\" valid-before=\"202409011200Z\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertEquals(new AllowedSigners.AllowedEntry( + new String[] { "foo@a.com" }, + false, new String[] { "git" }, + Instant.parse("2024-09-01T03:30:00.00Z"), + Instant.parse("2024-09-01T12:00:00.00Z"), + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGxkz2AUld8eitmyIYlVV+Sot4jT3CigyBmvFRff0q4cSsKLx4x2TxGQeKKVueJEawtsUC2GNRV9FxXsTCUGcZU="), + AllowedSigners.parseLine( + "foo@a.com namespaces=\"git\" valid-after=\"20240901\" valid-before=\"202409011200Z\" ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGxkz2AUld8eitmyIYlVV+Sot4jT3CigyBmvFRff0q4cSsKLx4x2TxGQeKKVueJEawtsUC2GNRV9FxXsTCUGcZU=")); + } + + @Test + public void testInvalidLine() { + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "cert-authority ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "namespaces=\"git\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "valid-after=\"20240901\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "valid-before=\"20240901\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO foo@bar.com")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "a@a.com namespaces=\"\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "a@a.com namespaces=\",,,\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + assertThrows(Exception.class, () -> AllowedSigners.parseLine( + "a@a.com,,b@a.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATOZ8PcOKdY978fzIstnZ0+FuefIWKp7wRZynQLdzO")); + } + + @Test + public void testSkippedLine() throws Exception { + assertNull(AllowedSigners.parseLine(null)); + assertNull(AllowedSigners.parseLine("")); + assertNull(AllowedSigners.parseLine("# Comment")); + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/OpenSshBinaryKrlLoadTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/OpenSshBinaryKrlLoadTest.java new file mode 100644 index 0000000..9f9c3ca --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/OpenSshBinaryKrlLoadTest.java
@@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertNotNull; + +import java.io.BufferedInputStream; +import java.io.InputStream; + +import org.junit.Test; + +/** + * Tests loading an {@link OpenSshBinaryKrl}. + */ +public class OpenSshBinaryKrlLoadTest { + + @Test + public void testLoad() throws Exception { + try (InputStream in = new BufferedInputStream( + this.getClass().getResourceAsStream("krl/krl"))) { + OpenSshBinaryKrl krl = OpenSshBinaryKrl.load(in, false); + assertNotNull(krl); + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/OpenSshKrlTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/OpenSshKrlTest.java new file mode 100644 index 0000000..2fd7756 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/OpenSshKrlTest.java
@@ -0,0 +1,146 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.List; + +import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; +import org.eclipse.jgit.util.FileUtils; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +/** + * Tests for {@link OpenSshKrl} using binary KRLs. + */ +@RunWith(Parameterized.class) +public class OpenSshKrlTest { + + // The test data was generated using the public domain OpenSSH test script + // with some minor modifications (une ed25519 always, generate a "includes + // everything KRl, name the unrekoked keys "unrevoked*", generate a plain + // text KRL, and don't run the ssh-keygen tests). The original script is + // available at + // https://github.com/openssh/openssh-portable/blob/67a115e/regress/krl.sh + + private static final String[] KRLS = { + "krl-empty", "krl-keys", "krl-all", + "krl-sha1", "krl-sha256", "krl-hash", + "krl-serial", "krl-keyid", "krl-cert", "krl-ca", + "krl-serial-wild", "krl-keyid-wild", "krl-text" }; + + private static final int[] REVOKED = { 1, 4, 10, 50, 90, 500, 510, 520, 550, + 799, 999 }; + + private static final int[] UNREVOKED = { 5, 9, 14, 16, 29, 49, 51, 499, 800, + 1010, 1011 }; + + private static class TestData { + + String key; + + String krl; + + Boolean expected; + + TestData(String key, String krl, boolean expected) { + this.key = key; + this.krl = krl; + this.expected = Boolean.valueOf(expected); + } + + @Override + public String toString() { + return key + '-' + krl; + } + } + + @Parameters(name = "{0}") + public static List<TestData> initTestData() { + List<TestData> tests = new ArrayList<>(); + for (int i = 0; i < REVOKED.length; i++) { + String key = String.format("revoked-%04d", + Integer.valueOf(REVOKED[i])); + for (String krl : KRLS) { + boolean expected = !krl.endsWith("-empty"); + tests.add(new TestData(key + "-cert.pub", krl, expected)); + expected = krl.endsWith("-keys") || krl.endsWith("-all") + || krl.endsWith("-hash") || krl.endsWith("-sha1") + || krl.endsWith("-sha256") || krl.endsWith("-text"); + tests.add(new TestData(key + ".pub", krl, expected)); + } + } + for (int i = 0; i < UNREVOKED.length; i++) { + String key = String.format("unrevoked-%04d", + Integer.valueOf(UNREVOKED[i])); + for (String krl : KRLS) { + boolean expected = false; + tests.add(new TestData(key + ".pub", krl, expected)); + expected = krl.endsWith("-ca"); + tests.add(new TestData(key + "-cert.pub", krl, expected)); + } + } + return tests; + } + + private static Path tmp; + + @BeforeClass + public static void setUp() throws IOException { + tmp = Files.createTempDirectory("krls"); + for (String krl : KRLS) { + copyResource("krl/" + krl, tmp); + } + } + + private static void copyResource(String name, Path directory) + throws IOException { + try (InputStream in = OpenSshKrlTest.class + .getResourceAsStream(name)) { + int i = name.lastIndexOf('/'); + String fileName = i < 0 ? name : name.substring(i + 1); + Files.copy(in, directory.resolve(fileName)); + } + } + + @AfterClass + public static void cleanUp() throws Exception { + FileUtils.delete(tmp.toFile(), FileUtils.RECURSIVE); + } + + // Injected by JUnit + @Parameter + public TestData data; + + @Test + public void testIsRevoked() throws Exception { + OpenSshKrl krl = new OpenSshKrl(tmp.resolve(data.krl)); + try (InputStream in = this.getClass() + .getResourceAsStream("krl/" + data.key)) { + PublicKey key = AuthorizedKeyEntry.readAuthorizedKeys(in, true) + .get(0) + .resolvePublicKey(null, PublicKeyEntryResolver.FAILING); + assertEquals(data.expected, Boolean.valueOf(krl.isRevoked(key))); + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SerialRangeSetTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SerialRangeSetTest.java new file mode 100644 index 0000000..e6709ad --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SerialRangeSetTest.java
@@ -0,0 +1,124 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Tests for the set of serial number ranges. + */ +public class SerialRangeSetTest { + + private SerialRangeSet ranges = new SerialRangeSet(); + + @Test + public void testInsertSimple() { + ranges.add(1); + ranges.add(3); + ranges.add(5); + assertEquals(3, ranges.size()); + assertFalse(ranges.contains(0)); + assertTrue(ranges.contains(1)); + assertFalse(ranges.contains(2)); + assertTrue(ranges.contains(3)); + assertFalse(ranges.contains(4)); + assertTrue(ranges.contains(5)); + assertFalse(ranges.contains(6)); + } + + @Test + public void testInsertSimpleRanges() { + ranges.add(1, 2); + ranges.add(4, 5); + ranges.add(7, 8); + assertEquals(3, ranges.size()); + assertFalse(ranges.contains(0)); + assertTrue(ranges.contains(1)); + assertTrue(ranges.contains(2)); + assertFalse(ranges.contains(3)); + assertTrue(ranges.contains(4)); + assertTrue(ranges.contains(5)); + assertFalse(ranges.contains(6)); + assertTrue(ranges.contains(7)); + assertTrue(ranges.contains(8)); + assertFalse(ranges.contains(9)); + } + + @Test + public void testInsertCoalesce() { + ranges.add(5); + ranges.add(1); + ranges.add(2); + ranges.add(4); + ranges.add(7); + ranges.add(3); + assertEquals(2, ranges.size()); + assertFalse(ranges.contains(0)); + assertTrue(ranges.contains(1)); + assertTrue(ranges.contains(2)); + assertTrue(ranges.contains(3)); + assertTrue(ranges.contains(4)); + assertTrue(ranges.contains(5)); + assertFalse(ranges.contains(6)); + assertTrue(ranges.contains(7)); + assertFalse(ranges.contains(8)); + } + + @Test + public void testInsertOverlap() { + ranges.add(1, 3); + ranges.add(6); + ranges.add(2, 5); + assertEquals(1, ranges.size()); + assertFalse(ranges.contains(0)); + assertTrue(ranges.contains(1)); + assertTrue(ranges.contains(2)); + assertTrue(ranges.contains(3)); + assertTrue(ranges.contains(4)); + assertTrue(ranges.contains(5)); + assertTrue(ranges.contains(6)); + assertFalse(ranges.contains(7)); + } + + @Test + public void testInsertOverlapMultiple() { + ranges.add(1, 3); + ranges.add(5, 6); + ranges.add(8); + ranges.add(2, 5); + assertEquals(2, ranges.size()); + assertFalse(ranges.contains(0)); + assertTrue(ranges.contains(1)); + assertTrue(ranges.contains(2)); + assertTrue(ranges.contains(3)); + assertTrue(ranges.contains(4)); + assertTrue(ranges.contains(5)); + assertTrue(ranges.contains(6)); + assertFalse(ranges.contains(7)); + assertTrue(ranges.contains(8)); + assertFalse(ranges.contains(9)); + } + + @Test + public void testInsertOverlapTotal() { + ranges.add(1, 3); + ranges.add(2, 3); + assertEquals(1, ranges.size()); + assertFalse(ranges.contains(0)); + assertTrue(ranges.contains(1)); + assertTrue(ranges.contains(2)); + assertTrue(ranges.contains(3)); + assertFalse(ranges.contains(4)); + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshCertificateUtilsTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshCertificateUtilsTest.java new file mode 100644 index 0000000..79ca21f --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshCertificateUtilsTest.java
@@ -0,0 +1,107 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.InputStream; +import java.security.PublicKey; +import java.time.Instant; +import java.util.List; + +import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; +import org.apache.sshd.common.util.buffer.Buffer; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for {@link SshCertificateUtils}. They use a certificate valid from + * 2024-09-01 00:00:00 to 2024-09-02 00:00:00 UTC. + */ +public class SshCertificateUtilsTest { + + private OpenSshCertificate certificate; + + @Before + public void loadCertificate() throws Exception { + try (InputStream in = this.getClass().getResourceAsStream( + "certs/expired.cert")) { + List<AuthorizedKeyEntry> keys = AuthorizedKeyEntry + .readAuthorizedKeys(in, true); + if (keys.isEmpty()) { + certificate = null; + } + PublicKey key = keys.get(0).resolvePublicKey(null, + PublicKeyEntryResolver.FAILING); + assertTrue( + "Expected an OpenSshKeyCertificate but got a " + + key.getClass().getName(), + key instanceof OpenSshCertificate); + certificate = (OpenSshCertificate) key; + } + } + + @Test + public void testValidUserCertificate() { + assertNull(SshCertificateUtils.verify(certificate, null)); + Instant validTime = Instant.parse("2024-09-01T00:00:00.00Z"); + assertNull(SshCertificateUtils.verify(certificate, validTime)); + assertNull(SshCertificateUtils.checkExpiration(certificate, validTime)); + } + + @Test + public void testCheckTooEarly() { + Instant invalidTime = Instant.parse("2024-08-31T23:59:59.00Z"); + assertNotNull( + SshCertificateUtils.checkExpiration(certificate, invalidTime)); + assertNotNull(SshCertificateUtils.verify(certificate, invalidTime)); + } + + @Test + public void testCheckExpired() { + Instant invalidTime = Instant.parse("2024-09-02T00:00:01.00Z"); + assertNotNull( + SshCertificateUtils.checkExpiration(certificate, invalidTime)); + assertNotNull(SshCertificateUtils.verify(certificate, invalidTime)); + } + + @Test + public void testInvalidSignature() throws Exception { + // Modify the serialized certificate, then re-load it again. To check that + // serialization per se works fine, also check an unmodified version. + Buffer buffer = new ByteArrayBuffer(); + buffer.putPublicKey(certificate); + int pos = buffer.rpos(); + PublicKey unchanged = buffer.getPublicKey(); + assertTrue( + "Expected an OpenSshCertificate but got a " + + unchanged.getClass().getName(), + unchanged instanceof OpenSshCertificate); + assertNull(SshCertificateUtils.verify((OpenSshCertificate) unchanged, + null)); + buffer.rpos(pos); + // Change a byte. The test certificate has the key ID at offset 128. + // Changing a byte in the key ID should still result in a successful + // deserialization, but then fail the signature check. + buffer.array()[pos + 128]++; + PublicKey changed = buffer.getPublicKey(); + assertTrue( + "Expected an OpenSshCertificate but got a " + + changed.getClass().getName(), + changed instanceof OpenSshCertificate); + assertNotNull( + SshCertificateUtils.verify((OpenSshCertificate) changed, null)); + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshSignatureVerifierTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshSignatureVerifierTest.java new file mode 100644 index 0000000..e5dfe49 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshSignatureVerifierTest.java
@@ -0,0 +1,151 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.VerificationResult; +import org.eclipse.jgit.lib.SignatureVerifier; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.StringUtils; +import org.junit.Test; + +/** + * Tests for the {@link SshSignatureVerifier}. + */ +public class SshSignatureVerifierTest extends AbstractSshSignatureTest { + + @Test + public void testPlainSignature() throws Exception { + RevCommit c = checkSshSignature( + createSignedCommit(null, "signing_key.pub")); + try (Git git = new Git(db)) { + Map<String, VerificationResult> results = git.verifySignature() + .addName(c.getName()).call(); + assertEquals(1, results.size()); + VerificationResult verified = results.get(c.getName()); + assertNotNull(verified); + assertNull(verified.getException()); + SignatureVerifier.SignatureVerification v = verified + .getVerification(); + assertTrue(v.verified()); + assertFalse(v.expired()); + assertTrue(StringUtils.isEmptyOrNull(v.message())); + assertEquals("tester@example.com", v.keyUser()); + assertEquals("SHA256:GKW0xy+XKnJGs0CJqP6j5bd4FdiwWNaUbwvUbHvhQKo", + v.keyFingerprint()); + assertEquals(SignatureVerifier.TrustLevel.FULL, v.trustLevel()); + assertEquals(commitTime, v.creationDate().toInstant()); + } + } + + @Test + public void testCertificateSignature() throws Exception { + RevCommit c = checkSshSignature( + createSignedCommit("tester.cert", "signing_key-cert.pub")); + try (Git git = new Git(db)) { + Map<String, VerificationResult> results = git.verifySignature() + .addName(c.getName()).call(); + assertEquals(1, results.size()); + VerificationResult verified = results.get(c.getName()); + assertNotNull(verified); + assertNull(verified.getException()); + SignatureVerifier.SignatureVerification v = verified + .getVerification(); + assertTrue(v.verified()); + assertFalse(v.expired()); + assertTrue(StringUtils.isEmptyOrNull(v.message())); + assertEquals("tester@example.com", v.keyUser()); + assertEquals("SHA256:GKW0xy+XKnJGs0CJqP6j5bd4FdiwWNaUbwvUbHvhQKo", + v.keyFingerprint()); + assertEquals(SignatureVerifier.TrustLevel.FULL, v.trustLevel()); + assertEquals(commitTime, v.creationDate().toInstant()); + } + } + + @Test + public void testNoPrincipalsSignature() throws Exception { + RevCommit c = checkSshSignature(createSignedCommit("no_principals.cert", + "signing_key-cert.pub")); + try (Git git = new Git(db)) { + Map<String, VerificationResult> results = git.verifySignature() + .addName(c.getName()).call(); + assertEquals(1, results.size()); + VerificationResult verified = results.get(c.getName()); + assertNotNull(verified); + assertNull(verified.getException()); + SignatureVerifier.SignatureVerification v = verified + .getVerification(); + assertFalse(v.verified()); + assertFalse(v.expired()); + assertNull(v.keyUser()); + assertEquals("SHA256:GKW0xy+XKnJGs0CJqP6j5bd4FdiwWNaUbwvUbHvhQKo", + v.keyFingerprint()); + assertEquals(SignatureVerifier.TrustLevel.NEVER, v.trustLevel()); + assertTrue(v.message().contains("*@example.com")); + assertEquals(commitTime, v.creationDate().toInstant()); + } + } + + @Test + public void testOtherCertificateSignature() throws Exception { + RevCommit c = checkSshSignature( + createSignedCommit("other.cert", "signing_key-cert.pub")); + try (Git git = new Git(db)) { + Map<String, VerificationResult> results = git.verifySignature() + .addName(c.getName()).call(); + assertEquals(1, results.size()); + VerificationResult verified = results.get(c.getName()); + assertNotNull(verified); + assertNull(verified.getException()); + SignatureVerifier.SignatureVerification v = verified + .getVerification(); + assertTrue(v.verified()); + assertFalse(v.expired()); + assertTrue(StringUtils.isEmptyOrNull(v.message())); + assertEquals("other@example.com", v.keyUser()); + assertEquals("SHA256:GKW0xy+XKnJGs0CJqP6j5bd4FdiwWNaUbwvUbHvhQKo", + v.keyFingerprint()); + assertEquals(SignatureVerifier.TrustLevel.FULL, v.trustLevel()); + assertEquals(commitTime, v.creationDate().toInstant()); + } + } + + @Test + public void testTwoPrincipalsCertificateSignature() throws Exception { + RevCommit c = checkSshSignature(createSignedCommit( + "two_principals.cert", "signing_key-cert.pub")); + try (Git git = new Git(db)) { + Map<String, VerificationResult> results = git.verifySignature() + .addName(c.getName()).call(); + assertEquals(1, results.size()); + VerificationResult verified = results.get(c.getName()); + assertNotNull(verified); + assertNull(verified.getException()); + SignatureVerifier.SignatureVerification v = verified + .getVerification(); + assertTrue(v.verified()); + assertFalse(v.expired()); + assertTrue(StringUtils.isEmptyOrNull(v.message())); + assertEquals("foo@example.com,tester@example.com", v.keyUser()); + assertEquals("SHA256:GKW0xy+XKnJGs0CJqP6j5bd4FdiwWNaUbwvUbHvhQKo", + v.keyFingerprint()); + assertEquals(SignatureVerifier.TrustLevel.FULL, v.trustLevel()); + assertEquals(commitTime, v.creationDate().toInstant()); + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshSignerTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshSignerTest.java new file mode 100644 index 0000000..b3a4482 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/SshSignerTest.java
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +import org.junit.Test; + +/** + * Tests for the {@link SshSigner}. + */ +public class SshSignerTest extends AbstractSshSignatureTest { + + @Test + public void testPlainSignature() throws Exception { + checkSshSignature(createSignedCommit(null, "signing_key.pub")); + } + + @Test + public void testExpiredSignature() throws Exception { + Throwable t = assertThrows(Throwable.class, + () -> createSignedCommit("expired.cert", + "signing_key-cert.pub")); + // The exception or one of its causes should mention "[Ee]xpired" and + // "[Cc]ertificate" in the message + while (t != null) { + String message = t.getMessage(); + if (message.contains("xpired") && message.contains("ertificate")) { + return; + } + t = t.getCause(); + } + fail("Expected exception message not found"); + } + + @Test + public void testCertificateSignature() throws Exception { + checkSshSignature(createSignedCommit("tester.cert", "signing_key.pub")); + } + + @Test + public void testNoPrincipalsSignature() throws Exception { + // Certificate has no principals; should still work + checkSshSignature( + createSignedCommit("no_principals.cert", "signing_key.pub")); + } + + @Test + public void testOtherSignature() throws Exception { + // Certificate has a principal different that tester@example.com; should + // still work + checkSshSignature(createSignedCommit("other.cert", "signing_key.pub")); + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/VerifyGitSignaturesTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/VerifyGitSignaturesTest.java new file mode 100644 index 0000000..30ddee5 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/VerifyGitSignaturesTest.java
@@ -0,0 +1,154 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.VerificationResult; +import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.SignatureVerifier; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.util.GitDateFormatter; +import org.eclipse.jgit.util.SignatureUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Verifies signatures made with C git and OpenSSH 9.0 to ensure we arrive at + * the same good/bad decisions, and that we can verify signatures not created by + * ourselves. + * <p> + * Clones a JGit repo from a git bundle file created with C git, then checks all + * the commits and their signatures. (All commits in that bundle have SSH + * signatures.) + * </p> + */ +public class VerifyGitSignaturesTest extends LocalDiskRepositoryTestCase { + + private static final Logger LOG = LoggerFactory + .getLogger(VerifyGitSignaturesTest.class); + + @Rule + public TemporaryFolder bundleDir = new TemporaryFolder(); + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + try (InputStream in = this.getClass() + .getResourceAsStream("repo.bundle")) { + Files.copy(in, bundleDir.getRoot().toPath().resolve("repo.bundle")); + } + try (InputStream in = this.getClass() + .getResourceAsStream("allowed_signers")) { + Files.copy(in, + bundleDir.getRoot().toPath().resolve("allowed_signers")); + } + } + + /** + * Tests signatures created by C git using OpenSSH 9.0. + */ + @Test + public void testGitSignatures() throws Exception { + File gitDir = new File(getTemporaryDirectory(), "repo.git"); + try (Git git = Git.cloneRepository().setBare(true) + .setGitDir(gitDir) + .setURI(new File(bundleDir.getRoot(), "repo.bundle").toURI() + .toString()) + .setBranch("master") + .call()) { + StoredConfig config = git.getRepository().getConfig(); + config.setString("gpg", "ssh", "allowedSignersFile", + bundleDir.getRoot().toPath().resolve("allowed_signers") + .toAbsolutePath().toString().replace('\\', '/')); + config.save(); + List<String> commits = new ArrayList<>(); + Map<String, PersonIdent> committers = new HashMap<>(); + git.log().all().call().forEach(c -> { + commits.add(c.getName()); + committers.put(c.getName(), c.getCommitterIdent()); + }); + Map<String, Boolean> expected = new HashMap<>(); + // These two commits do have multiple principals. GIT just reports + // the first one; we report both. + expected.put("9f79a7b661a22ab1ddf8af880d23678ae7696b71", + Boolean.TRUE); + expected.put("435108d157440e77d61a914b6a5736bc831c874d", + Boolean.TRUE); + // This commit has a wrong commit message; the certificate used + // did _not_ have two principals, but only a single principal + // foo@example.org. + expected.put("779dac7de40ebc3886af87d5e6680a09f8b13a3e", + Boolean.TRUE); + // Signed with other_key-cert.pub: we still don't know the key, + // but we do know the certificate's CA key, and trust it, so it's + // accepted as a signature from the principal(s) listed in the + // certificate. + expected.put("951f06d5b5598b721b98d98b04e491f234c1926a", + Boolean.TRUE); + // Signature with other_key.pub not listed in allowed_signers + expected.put("984e629c6d543a7f77eb49a8c9316f2ae4416375", + Boolean.FALSE); + // Signed with other-ca.cert (CA key not in allowed_signers), but + // the certified key _is_ listed in allowed_signers. + expected.put("1d7ac6d91747a9c9a777df238fbdaeffa7731a6c", + Boolean.FALSE); + expected.put("a297bcfbf5c4a850f9770655fef7315328a4b3fb", + Boolean.TRUE); + expected.put("852729d54676cb83826ed821dc7734013e97950d", + Boolean.TRUE); + // Signature with a certificate without principals. + expected.put("e39a049f75fe127eb74b30aba4b64e171d4281dd", + Boolean.FALSE); + // Signature made with expired.cert (expired at the commit time). + // git/OpenSSH 9.0 allows to create such signatures, but reports + // them as FALSE. Our SshSigner doesn't allow creating such + // signatures. + expected.put("303ea5e61feacdad4cb012b4cb6b0cea3fbcef9f", + Boolean.FALSE); + expected.put("1ae4b120a869b72a7a2d4ad4d7a8c9d454384333", + Boolean.TRUE); + Map<String, VerificationResult> results = git.verifySignature() + .addNames(commits).call(); + GitDateFormatter dateFormat = new GitDateFormatter( + GitDateFormatter.Format.ISO); + for (String oid : commits) { + VerificationResult v = results.get(oid); + assertNotNull(v); + assertNull(v.getException()); + SignatureVerifier.SignatureVerification sv = v + .getVerification(); + assertNotNull(sv); + LOG.info("Commit {}\n{}", oid, SignatureUtils.toString(sv, + committers.get(oid), dateFormat)); + Boolean wanted = expected.get(oid); + assertNotNull(wanted); + assertEquals(wanted, Boolean.valueOf(sv.verified())); + } + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReaderTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReaderTest.java new file mode 100644 index 0000000..d36c38f --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReaderTest.java
@@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.transport.sshd; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.apache.sshd.client.config.hosts.KnownHostEntry; +import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.junit.Test; + +public class KnownHostEntryReaderTest { + + @Test + public void testUnsupportedHostKeyLine() { + KnownHostEntry entry = KnownHostEntryReader.parseHostEntry( + "[localhost]:2222 ssh-unknown AAAAC3NzaC1lZDI1NTE5AAAAIPu6ntmyfSOkqLl3qPxD5XxwW7OONwwSG3KO+TGn+PFu"); + AuthorizedKeyEntry keyEntry = entry.getKeyEntry(); + assertNotNull(keyEntry); + assertEquals("ssh-unknown", keyEntry.getKeyType()); + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java new file mode 100644 index 0000000..6b61821 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java
@@ -0,0 +1,586 @@ +/* + * Copyright (C) 2025 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.transport.sshd; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.certificate.OpenSshCertificateBuilder; +import org.apache.sshd.common.SshConstants; +import org.apache.sshd.common.cipher.ECCurves; +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.PublicKeyEntry; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.errors.UnsupportedCredentialItem; +import org.eclipse.jgit.transport.CredentialItem; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.sshd.ServerKeyDatabase; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +/** + * Tests for {@link OpenSshServerKeyDatabase}. + */ +public class OpenSshServerKeyDatabaseTest { + + private static final InetSocketAddress LOCAL = new InetSocketAddress( + InetAddress.getLoopbackAddress(), SshConstants.DEFAULT_PORT); + + private static final InetSocketAddress LOCAL_29418 = new InetSocketAddress( + InetAddress.getLoopbackAddress(), 29418); + + private static PublicKey rsa1024; + private static PublicKey rsa2048; + private static PublicKey ec256; + private static PublicKey ec384; + private static PublicKey caKey; + private static PublicKey certificate; + + @BeforeClass + public static void initKeys() throws Exception { + // Generate a few keys that we can use + KeyPairGenerator gen = SecurityUtils.getKeyPairGenerator(KeyUtils.RSA_ALGORITHM); + gen.initialize(1024); + rsa1024 = gen.generateKeyPair().getPublic(); + gen.initialize(2048); + rsa2048 = gen.generateKeyPair().getPublic(); + gen = SecurityUtils.getKeyPairGenerator(KeyUtils.EC_ALGORITHM); + ECCurves curve = ECCurves.fromCurveSize(256); + gen.initialize(curve.getParameters()); + ec256 = gen.generateKeyPair().getPublic(); + PublicKey certKey = gen.generateKeyPair().getPublic(); + curve = ECCurves.fromCurveSize(384); + gen.initialize(curve.getParameters()); + ec384 = gen.generateKeyPair().getPublic(); + // Generate a certificate for some key + gen.initialize(curve.getParameters()); + KeyPair ca = gen.generateKeyPair(); + caKey = ca.getPublic(); + certificate = OpenSshCertificateBuilder + .hostCertificate() + .serial(System.currentTimeMillis()) + .publicKey(certKey) + .id("test-host-cert") + .validBefore( + System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)) + .principals(List.of("localhost", "127.0.0.1")) + .sign(ca, "ecdsa-sha2-nistp384"); + } + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + private Path knownHosts; + private Path knownHosts2; + private ServerKeyDatabase database; + + @Before + public void setupDatabase() throws Exception { + Path root = tmp.getRoot().toPath(); + knownHosts = root.resolve("known_hosts"); + knownHosts2 = root.resolve("known_hosts2"); + database = new OpenSshServerKeyDatabase(false, List.of(knownHosts, knownHosts2)); + } + + @Test + public void testFindInSecondFile() throws Exception { + Files.write(knownHosts, + List.of( + "some.other.host " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384))); + Files.write(knownHosts2, + List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048))); + assertTrue(database.accept("localhost", LOCAL, ec256, + new KnownHostsConfig(), null)); + assertFalse(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testNoFirstFile() throws Exception { + Files.write(knownHosts2, + List.of("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048))); + assertTrue(database.accept("localhost", LOCAL, ec256, + new KnownHostsConfig(), null)); + } + + @Test + public void testFind() throws Exception { + Files.write(knownHosts, + List.of("localhost,127.0.0.1 " + + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384))); + Files.write(knownHosts2, + List.of("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048))); + assertTrue(database.accept("localhost", LOCAL, ec256, + new KnownHostsConfig(), null)); + assertTrue(database.accept("localhost:22", LOCAL, ec256, + new KnownHostsConfig(), null)); + assertTrue(database.accept("127.0.0.1", LOCAL, rsa1024, + new KnownHostsConfig(), null)); + assertTrue(database.accept("[127.0.0.1]:22", LOCAL, rsa1024, + new KnownHostsConfig(), null)); + assertFalse(database.accept("localhost:29418", LOCAL_29418, ec256, + new KnownHostsConfig(), null)); + assertFalse(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testFindCertificate() throws Exception { + Files.write(knownHosts, + List.of("localhost,127.0.0.1 " + + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384), + "@cert-authority localhost,127.0.0.1 " + + PublicKeyEntry.toString(caKey))); + assertTrue(database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig(), null)); + } + + @Test + public void testCaKeyNotConsidered() throws Exception { + Files.write(knownHosts, + List.of("localhost,127.0.0.1 " + + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384), + "@cert-authority localhost,127.0.0.1 " + + PublicKeyEntry.toString(ec256))); + assertFalse(database.accept("localhost", LOCAL, ec256, + new KnownHostsConfig(), null)); + } + + @Test + public void testkeyPlainAndCa() throws Exception { + Files.write(knownHosts, List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384), + "@cert-authority localhost,127.0.0.1 " + + PublicKeyEntry.toString(ec256), + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256))); + // ec256 is a CA key, but also a valid direct host key for localhost + assertTrue(database.accept("localhost", LOCAL, ec256, + new KnownHostsConfig(), null)); + } + + @Test + public void testLookupCertificate() throws Exception { + List<PublicKey> keys = database.lookup("localhost", LOCAL, + new KnownHostsConfig()); + // Certificates or CA keys are not reported via lookup. + assertTrue(keys.isEmpty()); + } + + @Test + public void testCertificateNotAdded() throws Exception { + List<String> initialKnownHosts = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + assertFalse(database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig(), null)); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertFalse( + database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig( + KnownHostsConfig.StrictHostKeyChecking.ASK), + ui)); + assertEquals(0, ui.invocations); + assertFile(knownHosts, initialKnownHosts); + } + + @Test + public void testCertificateNotModified() throws Exception { + List<String> initialKnownHosts = List.of( + "@cert-authority localhost,127.0.0.1 " + + PublicKeyEntry.toString(ec384), + "some.other.com " + PublicKeyEntry.toString(ec256)); + Files.write(knownHosts, initialKnownHosts); + assertFalse(database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig(), null)); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertFalse( + database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig( + KnownHostsConfig.StrictHostKeyChecking.ASK), + ui)); + assertEquals(0, ui.invocations); + assertFile(knownHosts, initialKnownHosts); + } + + @Test + public void testModifyFile() throws Exception { + List<String> initialKnownHosts = List.of( + "some.other.host " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + assertFalse(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig(), null)); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, initialKnownHosts2); + assertFalse(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ACCEPT_NEW), + null)); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ACCEPT_ANY), + null)); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, initialKnownHosts2); + assertFalse(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + null)); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, initialKnownHosts2); + + TestCredentialsProvider ui = new TestCredentialsProvider(true, false); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, initialKnownHosts2); + + ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384), + "some.other.com " + PublicKeyEntry.toString(rsa2048))); + assertTrue(database.accept("127.0.0.1", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testModifyFirstFile() throws Exception { + List<String> initialKnownHosts = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List.of( + "some.other.host " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, + List.of("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384), + "some.other.com " + PublicKeyEntry.toString(ec384))); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("127.0.0.1:22", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testModifyMatchingKeyType() throws Exception { + List<String> initialKnownHosts = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, rsa2048, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, + List.of("localhost,127.0.0.1 " + + PublicKeyEntry.toString(rsa2048), + "some.other.com " + PublicKeyEntry.toString(ec384))); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("127.0.0.1:22", LOCAL, rsa2048, + new KnownHostsConfig(), null)); + } + + @Test + public void testModifyMatchingKeyType2() throws Exception { + List<String> initialKnownHosts = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, + List.of("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384), + "some.other.com " + PublicKeyEntry.toString(ec384))); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("127.0.0.1:22", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testModifySecondFile() throws Exception { + List<String> initialKnownHosts = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec256), + "some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, initialKnownHosts); + assertFile(knownHosts2, + List.of("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384), + "some.other.com " + PublicKeyEntry.toString(rsa2048))); + assertTrue(database.accept("127.0.0.1:22", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testAddNewKey() throws Exception { + List<String> initialKnownHosts = List.of( + "some.other.host " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec256)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List + .of("some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + List<String> expected = new ArrayList<>(initialKnownHosts); + expected.add("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384)); + assertFile(knownHosts, expected); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("127.0.0.1:22", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testCreateNewFile() throws Exception { + List<String> initialKnownHosts2 = List + .of("some.other.com " + PublicKeyEntry.toString(ec256)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + assertFile(knownHosts, List + .of("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384))); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("127.0.0.1:22", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testAddNewKey2() throws Exception { + List<String> initialKnownHosts = List.of( + "some.other.host " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec256)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List + .of("some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("127.0.0.1:29418", LOCAL_29418, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + List<String> expected = new ArrayList<>(initialKnownHosts); + expected.add("[127.0.0.1]:29418,[localhost]:29418 " + + PublicKeyEntry.toString(ec384)); + assertFile(knownHosts, expected); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("localhost:29418", LOCAL_29418, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testAddNewKey3() throws Exception { + List<String> initialKnownHosts = List.of( + "some.other.host " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec256)); + Files.write(knownHosts, initialKnownHosts); + List<String> initialKnownHosts2 = List + .of("some.other.com " + PublicKeyEntry.toString(rsa2048)); + Files.write(knownHosts2, initialKnownHosts2); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost:29418", LOCAL_29418, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + List<String> expected = new ArrayList<>(initialKnownHosts); + expected.add("[localhost]:29418,[127.0.0.1]:29418 " + + PublicKeyEntry.toString(ec384)); + assertFile(knownHosts, expected); + assertFile(knownHosts2, initialKnownHosts2); + assertTrue(database.accept("127.0.0.1:29418", LOCAL_29418, ec384, + new KnownHostsConfig(), null)); + } + + @Test + public void testUnknownKeyType() throws Exception { + List<String> initialKnownHosts = List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384) + .replace("ecdsa", "foo"), + "some.other.com " + PublicKeyEntry.toString(ec384)); + Files.write(knownHosts, initialKnownHosts); + TestCredentialsProvider ui = new TestCredentialsProvider(true, true); + assertTrue(database.accept("localhost", LOCAL, ec384, + new KnownHostsConfig( + ServerKeyDatabase.Configuration.StrictHostKeyChecking.ASK), + ui)); + assertEquals(1, ui.invocations); + // The "modified key" dialog has two questions; whereas the "add new + // key" is just a simple question. + assertEquals(2, ui.questions); + List<String> expected = new ArrayList<>(initialKnownHosts); + expected.add("localhost,127.0.0.1 " + PublicKeyEntry.toString(ec384)); + assertFile(knownHosts, expected); + assertTrue(database.accept("127.0.0.1:22", LOCAL, ec384, + new KnownHostsConfig(), null)); + } + + private void assertFile(Path path, List<String> lines) throws Exception { + assertEquals(lines, Files.readAllLines(path).stream() + .filter(s -> !s.isBlank()).toList()); + } + + private static class TestCredentialsProvider extends CredentialsProvider { + + private final boolean[] values; + + int invocations = 0; + + int questions = 0; + + TestCredentialsProvider(boolean accept, boolean store) { + values = new boolean[] { accept, store }; + } + + @Override + public boolean isInteractive() { + return true; + } + + @Override + public boolean supports(CredentialItem... items) { + return true; + } + + @Override + public boolean get(URIish uri, CredentialItem... items) + throws UnsupportedCredentialItem { + invocations++; + int i = 0; + for (CredentialItem item : items) { + if (item instanceof CredentialItem.YesNoType) { + ((CredentialItem.YesNoType) item) + .setValue(i < values.length && values[i++]); + questions++; + } + } + return true; + } + } + + private static class KnownHostsConfig implements ServerKeyDatabase.Configuration { + + @NonNull + private final StrictHostKeyChecking check; + + KnownHostsConfig() { + this(StrictHostKeyChecking.REQUIRE_MATCH); + } + + KnownHostsConfig(@NonNull StrictHostKeyChecking check) { + this.check = check; + } + + @Override + public List<String> getUserKnownHostsFiles() { + return List.of(); + } + + @Override + public List<String> getGlobalKnownHostsFiles() { + return List.of(); + } + + @Override + public StrictHostKeyChecking getStrictHostKeyChecking() { + return check; + } + + @Override + public boolean getHashKnownHosts() { + return false; + } + + @Override + public String getUsername() { + return "user"; + } + + } +}
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshProtocol2Test.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshProtocol2Test.java index eef0402..69bd5c5 100644 --- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshProtocol2Test.java +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshProtocol2Test.java
@@ -17,7 +17,6 @@ import org.eclipse.jgit.junit.ssh.SshBasicTestBase; import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.util.FS; @@ -52,7 +51,8 @@ protected void installConfig(String... config) { @Override public void setUp() throws Exception { super.setUp(); - StoredConfig config = ((Repository) db).getConfig(); + @SuppressWarnings("restriction") + StoredConfig config = db.getConfig(); config.setInt("protocol", null, "version", 2); config.save(); }
diff --git a/org.eclipse.jgit.ssh.apache/BUILD b/org.eclipse.jgit.ssh.apache/BUILD index fd88a8a..83709c3 100644 --- a/org.eclipse.jgit.ssh.apache/BUILD +++ b/org.eclipse.jgit.ssh.apache/BUILD
@@ -12,7 +12,6 @@ resource_strip_prefix = "org.eclipse.jgit.ssh.apache/resources", resources = RESOURCES, deps = [ - "//lib:eddsa", "//lib:slf4j-api", "//lib:sshd-osgi", "//lib:sshd-sftp",
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF index 02d9466..f38ea72 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -6,9 +6,10 @@ Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-ActivationPolicy: lazy -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.jgit.internal.transport.sshd;version="7.0.0";x-internal:=true; +Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.3.0";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.internal.transport.sshd;version="7.3.0";x-friends:="org.eclipse.jgit.ssh.apache.test"; uses:="org.apache.sshd.client, org.apache.sshd.client.auth, org.apache.sshd.client.auth.keyboard, @@ -23,78 +24,79 @@ org.apache.sshd.common.signature, org.apache.sshd.common.util.buffer, org.eclipse.jgit.transport", - org.eclipse.jgit.internal.transport.sshd.agent;version="7.0.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.auth;version="7.0.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.pkcs11;version="7.0.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.proxy;version="7.0.0";x-friends:="org.eclipse.jgit.ssh.apache.test", - org.eclipse.jgit.transport.sshd;version="7.0.0"; + org.eclipse.jgit.internal.transport.sshd.agent;version="7.3.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.auth;version="7.3.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.pkcs11;version="7.3.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.proxy;version="7.3.0";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.signing.ssh;version="7.3.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.transport.sshd;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.apache.sshd.client.config.hosts, org.apache.sshd.common.keyprovider, org.eclipse.jgit.util, org.apache.sshd.client.session, org.apache.sshd.client.keyverifier", - org.eclipse.jgit.transport.sshd.agent;version="7.0.0", - sun.security.x509 -Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)", - org.apache.sshd.agent;version="[2.12.0,2.13.0)", - org.apache.sshd.client;version="[2.12.0,2.13.0)", - org.apache.sshd.client.auth;version="[2.12.0,2.13.0)", - org.apache.sshd.client.auth.keyboard;version="[2.12.0,2.13.0)", - org.apache.sshd.client.auth.password;version="[2.12.0,2.13.0)", - org.apache.sshd.client.auth.pubkey;version="[2.12.0,2.13.0)", - org.apache.sshd.client.channel;version="[2.12.0,2.13.0)", - org.apache.sshd.client.config.hosts;version="[2.12.0,2.13.0)", - org.apache.sshd.client.config.keys;version="[2.12.0,2.13.0)", - org.apache.sshd.client.future;version="[2.12.0,2.13.0)", - org.apache.sshd.client.keyverifier;version="[2.12.0,2.13.0)", - org.apache.sshd.client.session;version="[2.12.0,2.13.0)", - org.apache.sshd.client.session.forward;version="[2.12.0,2.13.0)", - org.apache.sshd.common;version="[2.12.0,2.13.0)", - org.apache.sshd.common.auth;version="[2.12.0,2.13.0)", - org.apache.sshd.common.channel;version="[2.12.0,2.13.0)", - org.apache.sshd.common.cipher;version="[2.12.0,2.13.0)", - org.apache.sshd.common.compression;version="[2.12.0,2.13.0)", - org.apache.sshd.common.config.keys;version="[2.12.0,2.13.0)", - org.apache.sshd.common.config.keys.loader;version="[2.12.0,2.13.0)", - org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.12.0,2.13.0)", - org.apache.sshd.common.config.keys.u2f;version="[2.12.0,2.13.0)", - org.apache.sshd.common.digest;version="[2.12.0,2.13.0)", - org.apache.sshd.common.forward;version="[2.12.0,2.13.0)", - org.apache.sshd.common.future;version="[2.12.0,2.13.0)", - org.apache.sshd.common.helpers;version="[2.12.0,2.13.0)", - org.apache.sshd.common.io;version="[2.12.0,2.13.0)", - org.apache.sshd.common.kex;version="[2.12.0,2.13.0)", - org.apache.sshd.common.kex.extension;version="[2.12.0,2.13.0)", - org.apache.sshd.common.kex.extension.parser;version="[2.12.0,2.13.0)", - org.apache.sshd.common.keyprovider;version="[2.12.0,2.13.0)", - org.apache.sshd.common.mac;version="[2.12.0,2.13.0)", - org.apache.sshd.common.random;version="[2.12.0,2.13.0)", - org.apache.sshd.common.session;version="[2.12.0,2.13.0)", - org.apache.sshd.common.session.helpers;version="[2.12.0,2.13.0)", - org.apache.sshd.common.signature;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.buffer;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.buffer.keys;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.closeable;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.io;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.io.der;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.io.functors;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.io.resource;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.logging;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.net;version="[2.12.0,2.13.0)", - org.apache.sshd.common.util.security;version="[2.12.0,2.13.0)", - org.apache.sshd.core;version="[2.12.0,2.13.0)", - org.apache.sshd.server.auth;version="[2.12.0,2.13.0)", - org.apache.sshd.sftp;version="[2.12.0,2.13.0)", - org.apache.sshd.sftp.client;version="[2.12.0,2.13.0)", - org.apache.sshd.sftp.common;version="[2.12.0,2.13.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.fnmatch;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", + org.eclipse.jgit.transport.sshd.agent;version="7.3.0" +Import-Package: org.apache.sshd.agent;version="[2.15.0,2.16.0)", + org.apache.sshd.client;version="[2.15.0,2.16.0)", + org.apache.sshd.client.auth;version="[2.15.0,2.16.0)", + org.apache.sshd.client.auth.keyboard;version="[2.15.0,2.16.0)", + org.apache.sshd.client.auth.password;version="[2.15.0,2.16.0)", + org.apache.sshd.client.auth.pubkey;version="[2.15.0,2.16.0)", + org.apache.sshd.client.channel;version="[2.15.0,2.16.0)", + org.apache.sshd.client.config.hosts;version="[2.15.0,2.16.0)", + org.apache.sshd.client.config.keys;version="[2.15.0,2.16.0)", + org.apache.sshd.client.future;version="[2.15.0,2.16.0)", + org.apache.sshd.client.keyverifier;version="[2.15.0,2.16.0)", + org.apache.sshd.client.session;version="[2.15.0,2.16.0)", + org.apache.sshd.client.session.forward;version="[2.15.0,2.16.0)", + org.apache.sshd.common;version="[2.15.0,2.16.0)", + org.apache.sshd.common.auth;version="[2.15.0,2.16.0)", + org.apache.sshd.common.channel;version="[2.15.0,2.16.0)", + org.apache.sshd.common.cipher;version="[2.15.0,2.16.0)", + org.apache.sshd.common.compression;version="[2.15.0,2.16.0)", + org.apache.sshd.common.config.keys;version="[2.15.0,2.16.0)", + org.apache.sshd.common.config.keys.loader;version="[2.15.0,2.16.0)", + org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.15.0,2.16.0)", + org.apache.sshd.common.config.keys.u2f;version="[2.15.0,2.16.0)", + org.apache.sshd.common.digest;version="[2.15.0,2.16.0)", + org.apache.sshd.common.forward;version="[2.15.0,2.16.0)", + org.apache.sshd.common.future;version="[2.15.0,2.16.0)", + org.apache.sshd.common.helpers;version="[2.15.0,2.16.0)", + org.apache.sshd.common.io;version="[2.15.0,2.16.0)", + org.apache.sshd.common.kex;version="[2.15.0,2.16.0)", + org.apache.sshd.common.kex.extension;version="[2.15.0,2.16.0)", + org.apache.sshd.common.kex.extension.parser;version="[2.15.0,2.16.0)", + org.apache.sshd.common.keyprovider;version="[2.15.0,2.16.0)", + org.apache.sshd.common.mac;version="[2.15.0,2.16.0)", + org.apache.sshd.common.random;version="[2.15.0,2.16.0)", + org.apache.sshd.common.session;version="[2.15.0,2.16.0)", + org.apache.sshd.common.session.helpers;version="[2.15.0,2.16.0)", + org.apache.sshd.common.signature;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.buffer;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.buffer.keys;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.closeable;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.io;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.io.der;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.io.functors;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.io.resource;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.logging;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.net;version="[2.15.0,2.16.0)", + org.apache.sshd.common.util.security;version="[2.15.0,2.16.0)", + org.apache.sshd.core;version="[2.15.0,2.16.0)", + org.apache.sshd.server.auth;version="[2.15.0,2.16.0)", + org.apache.sshd.sftp;version="[2.15.0,2.16.0)", + org.apache.sshd.sftp.client;version="[2.15.0,2.16.0)", + org.apache.sshd.sftp.common;version="[2.15.0,2.16.0)", + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.fnmatch;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.slf4j;version="[1.7.0,3.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF index bb0d79b..d6225e2 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.ssh.apache - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml index 7cc3a55..365034a 100644 --- a/org.eclipse.jgit.ssh.apache/pom.xml +++ b/org.eclipse.jgit.ssh.apache/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache</artifactId> @@ -30,7 +30,6 @@ <properties> <translate-qualifier/> <source-bundle-manifest>${project.build.directory}/META-INF/SOURCE-MANIFEST.MF</source-bundle-manifest> - <eddsa-version>0.3.0</eddsa-version> </properties> <dependencies> @@ -63,12 +62,6 @@ </dependency> <dependency> - <groupId>net.i2p.crypto</groupId> - <artifactId>eddsa</artifactId> - <version>${eddsa-version}</version> - </dependency> - - <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency>
diff --git a/org.eclipse.jgit.ssh.apache/resources/META-INF/services/org.eclipse.jgit.lib.SignatureVerifierFactory b/org.eclipse.jgit.ssh.apache/resources/META-INF/services/org.eclipse.jgit.lib.SignatureVerifierFactory new file mode 100644 index 0000000..4a0f553 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/resources/META-INF/services/org.eclipse.jgit.lib.SignatureVerifierFactory
@@ -0,0 +1 @@ +org.eclipse.jgit.signing.ssh.SshSignatureVerifierFactory \ No newline at end of file
diff --git a/org.eclipse.jgit.ssh.apache/resources/META-INF/services/org.eclipse.jgit.lib.SignerFactory b/org.eclipse.jgit.ssh.apache/resources/META-INF/services/org.eclipse.jgit.lib.SignerFactory new file mode 100644 index 0000000..80f22c0 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/resources/META-INF/services/org.eclipse.jgit.lib.SignerFactory
@@ -0,0 +1 @@ +org.eclipse.jgit.signing.ssh.SshSignerFactory \ No newline at end of file
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 7da7181..773c4b9 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
@@ -61,6 +61,7 @@ The {0} key actually received has the fingerprints:\n\ {5}\n\ {6} +knownHostsRevokedCertificateMsg=Host ''{0}'' sent a certificate with a CA key that is marked as revoked in the known hosts file {1}. knownHostsRevokedKeyMsg=Host ''{0}'' sent a key that is marked as revoked in the known hosts file {1}. knownHostsUnknownKeyMsg=The authenticity of host ''{0}'' cannot be established. knownHostsUnknownKeyPrompt=Accept and store this key, and continue connecting? @@ -125,4 +126,69 @@ 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} +signAllowedSignersCertAuthorityError=Garbage after cert-authority +signAllowedSignersEmptyIdentity=Identities contains an empty identity; check for spurious extra commas: {0} +signAllowedSignersEmptyNamespaces=Empty namespaces= is not allowed; to allow a key for any namespace, omit the namespaces option +signAllowedSignersFormatError=Cannot parse allowed signers file {0}, problem at line {1}: {2} +signAllowedSignersInvalidDate=Cannot parse valid-before or valid-after date {0} +signAllowedSignersLineFormat=Invalid line format +signAllowedSignersMultiple={0} is allowed only once +signAllowedSignersNoIdentities=Line has no identity patterns +signAllowedSignersPublicKeyParsing=Cannot parse public key {0} +signAllowedSignersUnterminatedQuote=Unterminated double quote +signCertAlgorithmMismatch=Certificate of type {0} with CA key {1} uses an incompatible signature algorithm {2} +signCertAlgorithmUnknown=Certificate with CA key {0} is signed with an unknown algorithm {1} +signCertificateExpired=Expired certificate with CA key {0} +signCertificateInvalid=Certificate signature does not match on certificate with CA key {0} +signCertificateNotForName=Certificate with CA key {0} does not apply for name ''{1}'' +signCertificateRevoked=Certificate with CA key {0} was revoked +signCertificateTooEarly=Certificate with CA key {0} was not valid yet +signCertificateWithoutPrincipals=Certificate with CA key {0} has no principals; identities from gpg.ssh.allowedSignersFile: {1} +signDefaultKeyEmpty=git.ssh.defaultKeyCommand {0} returned no key +signDefaultKeyFailed=git.ssh.defaultKeyCommand {0} failed with exit code {1}\n{2} +signDefaultKeyInterrupted=git.ssh.defaultKeyCommand {0} was interrupted +signGarbageAtEnd=SSH signature has extra bytes at the end +signInvalidAlgorithm=SSH signature has invalid signature algorithm {0} +signInvalidKeyDSA=SSH signatures with DSA keys or certificates are not supported; use a different signing key. +signInvalidMagic=SSH signature does not start with "SSHSIG" +signInvalidNamespace=Namespace of SSH signature should be ''git'' but is ''{0}'' +signInvalidSignature=SSH signature is invalid: {0} +signInvalidVersion=Cannot verify signature with version {0} +signKeyExpired=Expired key used for SSH signature +signKeyRevoked=Key used for the SSH signature was revoked +signKeyTooEarly=Key used for the SSH signature was not valid yet +signKrlBlobLeftover=gpg.ssh.revocationFile has invalid blob section {0} with {1} leftover bytes +signKrlBlobLengthInvalid=gpg.ssh.revocationFile has invalid blob length {1} in section {0} +signKrlBlobLengthInvalidExpected=gpg.ssh.revocationFile has invalid blob length {1} (expected {2}) in section {0} +signKrlCaKeyLengthInvalid=gpg.ssh.revocationFile has invalid CA key length {0} in certificates section +signKrlCertificateLeftover=gpg.ssh.revocationFile has invalid certificates section with {0} leftover bytes +signKrlCertificateSubsectionLeftover=gpg.ssh.revocationFile has invalid certificates subsection with {0} leftover bytes +signKrlCertificateSubsectionLength=gpg.ssh.revocationFile has invalid certificates subsection length {0} +signKrlEmptyRange=gpg.ssh.revocationFile has an empty range of certificate serial numbers +signKrlInvalidBitSetLength=gpg.ssh.revocationFile has invalid certificate serial number bit set length {0} +signKrlInvalidKeyIdLength=gpg.ssh.revocationFile has invalid certificate key ID length {0} +signKrlInvalidMagic=gpg.ssh.revocationFile is not a binary OpenSSH key revocation list +signKrlInvalidReservedLength=gpg.ssh.revocationFile has an invalid reserved string length {0} +signKrlInvalidVersion=gpg.ssh.revocationFile: cannot read KRLs with FORMAT_VERSION {0} +signKrlNoCertificateSubsection=gpg.ssh.revocationFile has certificate section without subsections +signKrlSerialZero=gpg.ssh.revocationFile: certificate serial number zero cannot be revoked +signKrlShortRange=gpg.ssh.revocationFile: short certificate serial number range, need at least 8 more bytes, got only {0} +signKrlUnknownSection=gpg.ssh.revocationFile has an unknown section type {0} +signKrlUnknownSubsection=gpg.ssh.revocationFile has an unknown certificates subsection type {0} +signLogFailure=SSH signature verification failed +signMismatchedSignatureAlgorithm=SSH signature made with an ''{0}'' key has incompatible signature algorithm ''{1}'' +signNoAgent=No connector for ssh-agent found; maybe include org.eclipse.jgit.ssh.apache.agent in the application. +signNoPrincipalMatched=No principal matched in gpg.ssh.allowedSignersFile +signNoPublicKey=No public key found with signing key {0} +signNoSigningKey=Git config user.signingKey or gpg.ssh.defaultKeyCommand must be set for SSH signing. +signNotUserCertificate=Certificate with CA key {0} used for the SSH signature is not a user certificate. +signPublicKeyError=Cannot read public key {0} +signSeeLog=SSH signature verification failed; see the log for details +signSignatureError=Could not create the signature +signStderr=Cannot read stderr +signTooManyPrivateKeys=Private key file {0} must contain exactly one private key +signTooManyPublicKeys=Public key file {0} must contain exactly one public key +signUnknownHashAlgorithm=SSH Signature has an unknown hash algorithm {0} +signUnknownSignatureAlgorithm=SSH Signature has an unknown signature algorithm {0} +signWrongNamespace=Key may not be used in namespace "{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/signing/ssh/AllowedSigners.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/AllowedSigners.java new file mode 100644 index 0000000..80b171f --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/AllowedSigners.java
@@ -0,0 +1,530 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StreamCorruptedException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.security.PublicKey; +import java.text.MessageFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.config.keys.PublicKeyEntry; +import org.apache.sshd.common.util.io.ModifiableFileWatcher; +import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile; +import org.eclipse.jgit.internal.transport.sshd.SshdText; +import org.eclipse.jgit.signing.ssh.VerificationException; +import org.eclipse.jgit.util.StringUtils; +import org.eclipse.jgit.util.SystemReader; + +/** + * Encapsulates the allowed signers handling. + */ +final class AllowedSigners extends ModifiableFileWatcher { + + private static final String CERT_AUTHORITY = "cert-authority"; //$NON-NLS-1$ + + private static final String NAMESPACES = "namespaces="; //$NON-NLS-1$ + + private static final String VALID_AFTER = "valid-after="; //$NON-NLS-1$ + + private static final String VALID_BEFORE = "valid-before="; //$NON-NLS-1$ + + private static final DateTimeFormatter SSH_DATE_FORMAT = new DateTimeFormatterBuilder() + .appendValue(ChronoField.YEAR, 4) + .appendValue(ChronoField.MONTH_OF_YEAR, 2) + .appendValue(ChronoField.DAY_OF_MONTH, 2) + .optionalStart() + .appendValue(ChronoField.HOUR_OF_DAY, 2) + .appendValue(ChronoField.MINUTE_OF_HOUR, 2) + .optionalStart() + .appendValue(ChronoField.SECOND_OF_MINUTE, 2) + .toFormatter(Locale.ROOT); + + private static final Predicate<AllowedEntry> CERTIFICATES = AllowedEntry::isCA; + + private static final Predicate<AllowedEntry> PLAIN_KEYS = Predicate + .not(CERTIFICATES); + + @SuppressWarnings("ArrayRecordComponent") + static record AllowedEntry(String[] identities, boolean isCA, + String[] namespaces, Instant validAfter, Instant validBefore, + String key) { + // Empty + + @Override + public final boolean equals(Object any) { + if (this == any) { + return true; + } + if (any == null || !(any instanceof AllowedEntry)) { + return false; + } + AllowedEntry other = (AllowedEntry) any; + return isCA == other.isCA + && Arrays.equals(identities, other.identities) + && Arrays.equals(namespaces, other.namespaces) + && Objects.equals(validAfter, other.validAfter) + && Objects.equals(validBefore, other.validBefore) + && Objects.equals(key, other.key); + } + + @Override + public final int hashCode() { + int hash = Boolean.hashCode(isCA); + hash = hash * 31 + Arrays.hashCode(identities); + hash = hash * 31 + Arrays.hashCode(namespaces); + return hash * 31 + Objects.hash(validAfter, validBefore, key); + } + } + + private static record State(Map<String, List<AllowedEntry>> entries) { + // Empty + } + + private State state; + + public AllowedSigners(Path path) { + super(path); + state = new State(new HashMap<>()); + } + + public String isAllowed(PublicKey key, String namespace, String name, + Instant time) throws IOException, VerificationException { + State currentState = refresh(); + PublicKey keyToCheck = key; + if (key instanceof OpenSshCertificate certificate) { + AllowedEntry entry = find(currentState, certificate.getCaPubKey(), + namespace, name, time, CERTIFICATES); + if (entry != null) { + Collection<String> principals = certificate.getPrincipals(); + if (principals.isEmpty()) { + // According to the OpenSSH documentation, a certificate + // without principals is valid for anyone. + // + // See https://man.openbsd.org/ssh-keygen.1#CERTIFICATES . + // + // However, the same documentation also says that a name + // must match both the entry's patterns and be listed in the + // certificate's principals. + // + // See https://man.openbsd.org/ssh-keygen.1#ALLOWED_SIGNERS + // + // git/OpenSSH considers signatures made by such + // certificates untrustworthy. + String identities; + if (!StringUtils.isEmptyOrNull(name)) { + // The name must have matched entry.identities. + identities = name; + } else { + identities = Arrays.stream(entry.identities()) + .collect(Collectors.joining(",")); //$NON-NLS-1$ + } + throw new VerificationException(false, MessageFormat.format( + SshdText.get().signCertificateWithoutPrincipals, + KeyUtils.getFingerPrint(certificate.getCaPubKey()), + identities)); + } + if (!StringUtils.isEmptyOrNull(name)) { + if (!principals.contains(name)) { + throw new VerificationException(false, + MessageFormat.format(SshdText + .get().signCertificateNotForName, + KeyUtils.getFingerPrint( + certificate.getCaPubKey()), + name)); + } + return name; + } + // Filter the principals listed in the certificate by + // the patterns defined in the file. + Set<String> filtered = new LinkedHashSet<>(); + List<String> patterns = Arrays.asList(entry.identities()); + for (String principal : principals) { + if (OpenSshConfigFile.patternMatch(patterns, principal)) { + filtered.add(principal); + } + } + return filtered.stream().collect(Collectors.joining(",")); //$NON-NLS-1$ + } + // Certificate not found. git/OpenSSH considers this untrustworthy, + // even if the certified key itself might be listed. + return null; + // Alternative: go check for the certified key itself: + // keyToCheck = certificate.getCertPubKey(); + } + AllowedEntry entry = find(currentState, keyToCheck, namespace, name, + time, PLAIN_KEYS); + if (entry != null) { + if (!StringUtils.isEmptyOrNull(name)) { + // The name must have matched entry.identities. + return name; + } + // No name given, but we consider the key valid: report the + // identities. + return Arrays.stream(entry.identities()) + .collect(Collectors.joining(",")); //$NON-NLS-1$ + } + return null; + } + + private AllowedEntry find(State current, PublicKey key, + String namespace, String name, Instant time, + Predicate<AllowedEntry> filter) + throws VerificationException { + String k = PublicKeyEntry.toString(key); + VerificationException v = null; + List<AllowedEntry> candidates = current.entries().get(k); + if (candidates == null) { + return null; + } + for (AllowedEntry entry : candidates) { + if (!filter.test(entry)) { + continue; + } + if (name != null && !OpenSshConfigFile + .patternMatch(Arrays.asList(entry.identities()), name)) { + continue; + } + if (entry.namespaces() != null) { + if (!OpenSshConfigFile.patternMatch( + Arrays.asList(entry.namespaces()), + namespace)) { + if (v == null) { + v = new VerificationException(false, + MessageFormat.format( + SshdText.get().signWrongNamespace, + KeyUtils.getFingerPrint(key), + namespace)); + } + continue; + } + } + if (time != null) { + if (entry.validAfter() != null + && time.isBefore(entry.validAfter())) { + if (v == null) { + v = new VerificationException(true, + MessageFormat.format( + SshdText.get().signKeyTooEarly, + KeyUtils.getFingerPrint(key))); + } + continue; + } else if (entry.validBefore() != null + && time.isAfter(entry.validBefore())) { + if (v == null) { + v = new VerificationException(true, + MessageFormat.format( + SshdText.get().signKeyTooEarly, + KeyUtils.getFingerPrint(key))); + } + continue; + } + } + return entry; + } + if (v != null) { + throw v; + } + return null; + } + + private synchronized State refresh() throws IOException { + if (checkReloadRequired()) { + updateReloadAttributes(); + try { + state = reload(getPath()); + } catch (NoSuchFileException e) { + // File disappeared + resetReloadAttributes(); + state = new State(new HashMap<>()); + } + } + return state; + } + + private static State reload(Path path) throws IOException { + Map<String, List<AllowedEntry>> entries = new HashMap<>(); + try (BufferedReader r = Files.newBufferedReader(path, + StandardCharsets.UTF_8)) { + String line; + for (int lineNumber = 1;; lineNumber++) { + line = r.readLine(); + if (line == null) { + break; + } + line = line.strip(); + try { + AllowedEntry entry = parseLine(line); + if (entry != null) { + entries.computeIfAbsent(entry.key(), + k -> new ArrayList<>()).add(entry); + } + } catch (IOException | RuntimeException e) { + throw new IOException(MessageFormat.format( + SshdText.get().signAllowedSignersFormatError, path, + Integer.toString(lineNumber), line), e); + } + } + } + return new State(entries); + } + + private static boolean matches(String src, String other, int offset) { + return src.regionMatches(true, offset, other, 0, other.length()); + } + + // Things below have package visibility for testing. + + static AllowedEntry parseLine(String line) + throws IOException { + if (StringUtils.isEmptyOrNull(line) || line.charAt(0) == '#') { + return null; + } + int length = line.length(); + if ((matches(line, CERT_AUTHORITY, 0) + && CERT_AUTHORITY.length() < length + && Character.isWhitespace(line.charAt(CERT_AUTHORITY.length()))) + || matches(line, NAMESPACES, 0) + || matches(line, VALID_AFTER, 0) + || matches(line, VALID_BEFORE, 0)) { + throw new StreamCorruptedException( + SshdText.get().signAllowedSignersNoIdentities); + } + int i = 0; + while (i < length && !Character.isWhitespace(line.charAt(i))) { + i++; + } + if (i >= length) { + throw new StreamCorruptedException(SshdText.get().signAllowedSignersLineFormat); + } + String[] identities = line.substring(0, i).split(","); //$NON-NLS-1$ + if (Arrays.stream(identities).anyMatch(String::isEmpty)) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersEmptyIdentity, + line.substring(0, i))); + } + // Parse the options + i++; + boolean isCA = false; + List<String> namespaces = null; + Instant validAfter = null; + Instant validBefore = null; + while (i < length) { + // Skip whitespace + if (Character.isSpaceChar(line.charAt(i))) { + i++; + continue; + } + if (matches(line, CERT_AUTHORITY, i)) { + i += CERT_AUTHORITY.length(); + isCA = true; + if (!Character.isWhitespace(line.charAt(i))) { + throw new StreamCorruptedException(SshdText.get().signAllowedSignersCertAuthorityError); + } + i++; + } else if (matches(line, NAMESPACES, i)) { + if (namespaces != null) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersMultiple, + NAMESPACES)); + } + i += NAMESPACES.length(); + Dequoted parsed = dequote(line, i); + i = parsed.after(); + String ns = parsed.value(); + String[] items = ns.split(","); //$NON-NLS-1$ + namespaces = new ArrayList<>(items.length); + for (int j = 0; j < items.length; j++) { + String n = items[j].strip(); + if (!n.isEmpty()) { + namespaces.add(n); + } + } + if (namespaces.isEmpty()) { + throw new StreamCorruptedException( + SshdText.get().signAllowedSignersEmptyNamespaces); + } + } else if (matches(line, VALID_AFTER, i)) { + if (validAfter != null) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersMultiple, + VALID_AFTER)); + } + i += VALID_AFTER.length(); + Dequoted parsed = dequote(line, i); + i = parsed.after(); + validAfter = parseDate(parsed.value()); + } else if (matches(line, VALID_BEFORE, i)) { + if (validBefore != null) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersMultiple, + VALID_BEFORE)); + } + i += VALID_BEFORE.length(); + Dequoted parsed = dequote(line, i); + i = parsed.after(); + validBefore = parseDate(parsed.value()); + } else { + break; + } + } + // Now we should be at the key + String key = parsePublicKey(line, i); + return new AllowedEntry(identities, isCA, + namespaces == null ? null : namespaces.toArray(new String[0]), + validAfter, validBefore, key); + } + + static String parsePublicKey(String s, int from) + throws StreamCorruptedException { + int i = from; + int length = s.length(); + while (i < length && Character.isWhitespace(s.charAt(i))) { + i++; + } + if (i >= length) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersPublicKeyParsing, + s.substring(from))); + } + int start = i; + while (i < length && !Character.isWhitespace(s.charAt(i))) { + i++; + } + if (i >= length) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersPublicKeyParsing, + s.substring(start))); + } + int endOfKeyType = i; + i = endOfKeyType + 1; + while (i < length && Character.isWhitespace(s.charAt(i))) { + i++; + } + int startOfKey = i; + while (i < length && !Character.isWhitespace(s.charAt(i))) { + i++; + } + if (i == startOfKey) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersPublicKeyParsing, + s.substring(start))); + } + String keyType = s.substring(start, endOfKeyType); + String key = s.substring(startOfKey, i); + if (!key.startsWith("AAAA")) { //$NON-NLS-1$ + // base64 encoded SSH keys always start with four 'A's. + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signAllowedSignersPublicKeyParsing, + s.substring(start))); + } + return keyType + ' ' + s.substring(startOfKey, i); + } + + static Instant parseDate(String input) { + // Allowed formats are YYYYMMDD[Z] or YYYYMMDDHHMM[SS][Z]. If 'Z', it's + // UTC, otherwise local time. + String timeSpec = input; + int length = input.length(); + if (length < 8) { + throw new IllegalArgumentException(MessageFormat.format( + SshdText.get().signAllowedSignersInvalidDate, input)); + } + boolean isUTC = false; + if (timeSpec.charAt(length - 1) == 'Z') { + isUTC = true; + timeSpec = timeSpec.substring(0, length - 1); + } + LocalDateTime time; + TemporalAccessor temporalAccessor = SSH_DATE_FORMAT.parseBest(timeSpec, + LocalDateTime::from, LocalDate::from); + if (temporalAccessor instanceof LocalDateTime) { + time = (LocalDateTime) temporalAccessor; + } else { + time = ((LocalDate) temporalAccessor).atStartOfDay(); + } + if (isUTC) { + return time.atOffset(ZoneOffset.UTC).toInstant(); + } + ZoneId tz = SystemReader.getInstance().getTimeZoneId(); + return time.atZone(tz).toInstant(); + } + + // OpenSSH uses the backslash *only* to quote the double-quote. + static Dequoted dequote(String line, int from) { + int length = line.length(); + int i = from; + if (line.charAt(i) == '"') { + boolean quoted = false; + i++; + StringBuilder b = new StringBuilder(); + while (i < length) { + char ch = line.charAt(i); + if (ch == '"') { + if (quoted) { + b.append(ch); + quoted = false; + } else { + break; + } + } else if (ch == '\\') { + quoted = true; + } else { + if (quoted) { + b.append('\\'); + } + b.append(ch); + quoted = false; + } + i++; + } + if (i >= length) { + throw new IllegalArgumentException( + SshdText.get().signAllowedSignersUnterminatedQuote); + } + return new Dequoted(b.toString(), i + 1); + } + while (i < length && !Character.isWhitespace(line.charAt(i))) { + i++; + } + return new Dequoted(line.substring(from, i), i); + } + + static record Dequoted(String value, int after) { + // Empty + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshBinaryKrl.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshBinaryKrl.java new file mode 100644 index 0000000..6b19eb32 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshBinaryKrl.java
@@ -0,0 +1,491 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.StreamCorruptedException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.util.buffer.BufferUtils; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.internal.transport.sshd.SshdText; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.StringUtils; + +/** + * An implementation of OpenSSH binary format key revocation lists (KRLs). + * + * @see <a href= + * "https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.krl">PROTOCOL.krl</a> + */ +class OpenSshBinaryKrl { + + /** + * The "magic" bytes at the start of an OpenSSH binary KRL. + */ + static final byte[] MAGIC = { 'S', 'S', 'H', 'K', 'R', 'L', '\n', 0 }; + + private static final int FORMAT_VERSION = 1; + + private static final int SECTION_CERTIFICATES = 1; + + private static final int SECTION_KEY = 2; + + private static final int SECTION_SHA1 = 3; + + private static final int SECTION_SIGNATURE = 4; // Skipped + + private static final int SECTION_SHA256 = 5; + + private static final int SECTION_EXTENSION = 255; // Skipped + + // Certificates + + private static final int CERT_SERIAL_LIST = 0x20; + + private static final int CERT_SERIAL_RANGES = 0x21; + + private static final int CERT_SERIAL_BITS = 0x22; + + private static final int CERT_KEY_IDS = 0x23; + + private static final int CERT_EXTENSIONS = 0x39; // Skipped + + private final Map<Blob, CertificateRevocation> certificates = new HashMap<>(); + + private static class CertificateRevocation { + + final SerialRangeSet ranges = new SerialRangeSet(); + + final Set<String> keyIds = new HashSet<>(); + } + + // Plain keys + + /** + * A byte array that can be used as a key in a {@link Map} or {@link Set}. + * {@link #equals(Object)} and {@link #hashCode()} are based on the content. + * + * @param blob + * the array to wrap + */ + @SuppressWarnings("ArrayRecordComponent") + private static record Blob(byte[] blob) { + + @Override + public final boolean equals(Object any) { + if (this == any) { + return true; + } + if (any == null || !(any instanceof Blob)) { + return false; + } + Blob other = (Blob) any; + return Arrays.equals(blob, other.blob); + } + + @Override + public final int hashCode() { + return Arrays.hashCode(blob); + } + } + + private final Set<Blob> blobs = new HashSet<>(); + + private final Set<Blob> sha1 = new HashSet<>(); + + private final Set<Blob> sha256 = new HashSet<>(); + + private OpenSshBinaryKrl() { + // No public instantiation, use load(InputStream, boolean) instead. + } + + /** + * Tells whether the given key has been revoked. + * + * @param key + * {@link PublicKey} to check + * @return {@code true} if the key was revoked, {@code false} otherwise + */ + boolean isRevoked(PublicKey key) { + if (key instanceof OpenSshCertificate certificate) { + if (certificates.isEmpty()) { + return false; + } + // These apply to all certificates + if (isRevoked(certificate, certificates.get(null))) { + return true; + } + if (isRevoked(certificate, + certificates.get(blob(certificate.getCaPubKey())))) { + return true; + } + // Keys themselves are checked in OpenSshKrl. + return false; + } + if (!blobs.isEmpty() && blobs.contains(blob(key))) { + return true; + } + if (!sha256.isEmpty() && sha256.contains(hash("SHA256", key))) { //$NON-NLS-1$ + return true; + } + if (!sha1.isEmpty() && sha1.contains(hash("SHA1", key))) { //$NON-NLS-1$ + return true; + } + return false; + } + + private boolean isRevoked(OpenSshCertificate certificate, + CertificateRevocation revocations) { + if (revocations == null) { + return false; + } + String id = certificate.getId(); + if (!StringUtils.isEmptyOrNull(id) && revocations.keyIds.contains(id)) { + return true; + } + long serial = certificate.getSerial(); + if (serial != 0 && revocations.ranges.contains(serial)) { + return true; + } + return false; + } + + private Blob blob(PublicKey key) { + ByteArrayBuffer buf = new ByteArrayBuffer(); + buf.putRawPublicKey(key); + return new Blob(buf.getCompactData()); + } + + private Blob hash(String algorithm, PublicKey key) { + ByteArrayBuffer buf = new ByteArrayBuffer(); + buf.putRawPublicKey(key); + try { + return new Blob(MessageDigest.getInstance(algorithm) + .digest(buf.getCompactData())); + } catch (NoSuchAlgorithmException e) { + throw new JGitInternalException(e.getMessage(), e); + } + } + + /** + * Loads a binary KRL from the given stream. + * + * @param in + * {@link InputStream} to read from + * @param magicSkipped + * whether the {@link #MAGIC} bytes at the beginning have already + * been skipped + * @return a new {@link OpenSshBinaryKrl}. + * @throws IOException + * if the stream cannot be read as an OpenSSH binary KRL + */ + @NonNull + static OpenSshBinaryKrl load(InputStream in, boolean magicSkipped) + throws IOException { + if (!magicSkipped) { + byte[] magic = new byte[MAGIC.length]; + IO.readFully(in, magic); + if (!Arrays.equals(magic, MAGIC)) { + throw new StreamCorruptedException( + SshdText.get().signKrlInvalidMagic); + } + } + skipHeader(in); + return load(in); + } + + private static long getUInt(InputStream in) throws IOException { + byte[] buf = new byte[Integer.BYTES]; + IO.readFully(in, buf); + return BufferUtils.getUInt(buf); + } + + private static long getLong(InputStream in) throws IOException { + byte[] buf = new byte[Long.BYTES]; + IO.readFully(in, buf); + return BufferUtils.getLong(buf, 0, Long.BYTES); + } + + private static void skipHeader(InputStream in) throws IOException { + long version = getUInt(in); + if (version != FORMAT_VERSION) { + throw new StreamCorruptedException( + MessageFormat.format(SshdText.get().signKrlInvalidVersion, + Long.valueOf(version))); + } + // krl_version, generated_date, flags (none defined in version 1) + in.skip(24); + in.skip(getUInt(in)); // reserved + in.skip(getUInt(in)); // comment + } + + private static OpenSshBinaryKrl load(InputStream in) throws IOException { + OpenSshBinaryKrl krl = new OpenSshBinaryKrl(); + for (;;) { + int sectionType = in.read(); + if (sectionType < 0) { + break; // EOF + } + switch (sectionType) { + case SECTION_CERTIFICATES: + readCertificates(krl.certificates, in, getUInt(in)); + break; + case SECTION_KEY: + readBlobs("explicit_keys", krl.blobs, in, getUInt(in), 0); //$NON-NLS-1$ + break; + case SECTION_SHA1: + readBlobs("fingerprint_sha1", krl.sha1, in, getUInt(in), 20); //$NON-NLS-1$ + break; + case SECTION_SIGNATURE: + // Unsupported as of OpenSSH 9.4. It even refuses to load such + // KRLs. Just skip it. + in.skip(getUInt(in)); + break; + case SECTION_SHA256: + readBlobs("fingerprint_sha256", krl.sha256, in, getUInt(in), //$NON-NLS-1$ + 32); + break; + case SECTION_EXTENSION: + // No extensions are defined for version 1 KRLs. + in.skip(getUInt(in)); + break; + default: + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlUnknownSection, + Integer.valueOf(sectionType))); + } + } + return krl; + } + + private static void readBlobs(String sectionName, Set<Blob> blobs, + InputStream in, long sectionLength, long expectedBlobLength) + throws IOException { + while (sectionLength >= Integer.BYTES) { + // Read blobs. + long blobLength = getUInt(in); + sectionLength -= Integer.BYTES; + if (blobLength > sectionLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlBlobLengthInvalid, sectionName, + Long.valueOf(blobLength))); + } + if (expectedBlobLength != 0 && blobLength != expectedBlobLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlBlobLengthInvalidExpected, + sectionName, Long.valueOf(blobLength), + Long.valueOf(expectedBlobLength))); + } + byte[] blob = new byte[(int) blobLength]; + IO.readFully(in, blob); + sectionLength -= blobLength; + blobs.add(new Blob(blob)); + } + if (sectionLength != 0) { + throw new StreamCorruptedException( + MessageFormat.format(SshdText.get().signKrlBlobLeftover, + sectionName, Long.valueOf(sectionLength))); + } + } + + private static void readCertificates(Map<Blob, CertificateRevocation> certs, + InputStream in, long sectionLength) throws IOException { + long keyLength = getUInt(in); + sectionLength -= Integer.BYTES; + if (keyLength > sectionLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCaKeyLengthInvalid, + Long.valueOf(keyLength))); + } + Blob key = null; + if (keyLength > 0) { + byte[] blob = new byte[(int) keyLength]; + IO.readFully(in, blob); + key = new Blob(blob); + sectionLength -= keyLength; + } + CertificateRevocation rev = certs.computeIfAbsent(key, + k -> new CertificateRevocation()); + long reservedLength = getUInt(in); + sectionLength -= Integer.BYTES; + if (reservedLength > sectionLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCaKeyLengthInvalid, + Long.valueOf(reservedLength))); + } + in.skip(reservedLength); + sectionLength -= reservedLength; + if (sectionLength == 0) { + throw new StreamCorruptedException( + SshdText.get().signKrlNoCertificateSubsection); + } + while (sectionLength > 0) { + int subSection = in.read(); + if (subSection < 0) { + throw new EOFException(); + } + sectionLength--; + if (sectionLength < Integer.BYTES) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCertificateLeftover, + Long.valueOf(sectionLength))); + } + long subLength = getUInt(in); + sectionLength -= Integer.BYTES; + if (subLength > sectionLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCertificateSubsectionLength, + Long.valueOf(subLength))); + } + if (subLength > 0) { + switch (subSection) { + case CERT_SERIAL_LIST: + readSerials(rev.ranges, in, subLength, false); + break; + case CERT_SERIAL_RANGES: + readSerials(rev.ranges, in, subLength, true); + break; + case CERT_SERIAL_BITS: + readSerialBitSet(rev.ranges, in, subLength); + break; + case CERT_KEY_IDS: + readIds(rev.keyIds, in, subLength); + break; + case CERT_EXTENSIONS: + in.skip(subLength); + break; + default: + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlUnknownSubsection, + Long.valueOf(subSection))); + } + } + sectionLength -= subLength; + } + } + + private static void readSerials(SerialRangeSet set, InputStream in, + long length, boolean ranges) throws IOException { + while (length >= Long.BYTES) { + long a = getLong(in); + length -= Long.BYTES; + if (a == 0) { + throw new StreamCorruptedException( + SshdText.get().signKrlSerialZero); + } + if (!ranges) { + set.add(a); + continue; + } + if (length < Long.BYTES) { + throw new StreamCorruptedException( + MessageFormat.format(SshdText.get().signKrlShortRange, + Long.valueOf(length))); + } + long b = getLong(in); + length -= Long.BYTES; + if (Long.compareUnsigned(a, b) > 0) { + throw new StreamCorruptedException( + SshdText.get().signKrlEmptyRange); + } + set.add(a, b); + } + if (length != 0) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCertificateSubsectionLeftover, + Long.valueOf(length))); + } + } + + private static void readSerialBitSet(SerialRangeSet set, InputStream in, + long subLength) throws IOException { + while (subLength > 0) { + if (subLength < Long.BYTES) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCertificateSubsectionLeftover, + Long.valueOf(subLength))); + } + long base = getLong(in); + subLength -= Long.BYTES; + if (subLength < Integer.BYTES) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCertificateSubsectionLeftover, + Long.valueOf(subLength))); + } + long setLength = getUInt(in); + subLength -= Integer.BYTES; + if (setLength == 0 || setLength > subLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlInvalidBitSetLength, + Long.valueOf(setLength))); + } + // Now process the bits. Note that the mpint is stored MSB first. + // + // We set individual serial numbers (one for each set bit) and let + // the SerialRangeSet take care of coalescing for successive runs + // of set bits. + int n = (int) setLength; + for (int i = n - 1; i >= 0; i--) { + int b = in.read(); + if (b < 0) { + throw new EOFException(); + } else if (b == 0) { + // Stored as an mpint: may have leading zero bytes (actually + // at most one; if the high bit of the first byte is set). + continue; + } + for (int bit = 0, + mask = 1; bit < Byte.SIZE; bit++, mask <<= 1) { + if ((b & mask) != 0) { + set.add(base + (i * Byte.SIZE) + bit); + } + } + } + subLength -= setLength; + } + } + + private static void readIds(Set<String> ids, InputStream in, long subLength) + throws IOException { + while (subLength >= Integer.BYTES) { + long length = getUInt(in); + subLength -= Integer.BYTES; + if (length > subLength) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlInvalidKeyIdLength, + Long.valueOf(length))); + } + byte[] bytes = new byte[(int) length]; + IO.readFully(in, bytes); + ids.add(new String(bytes, StandardCharsets.UTF_8)); + subLength -= length; + } + if (subLength != 0) { + throw new StreamCorruptedException(MessageFormat.format( + SshdText.get().signKrlCertificateSubsectionLeftover, + Long.valueOf(subLength))); + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshKrl.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshKrl.java new file mode 100644 index 0000000..7993def --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshKrl.java
@@ -0,0 +1,120 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.security.PublicKey; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.config.keys.PublicKeyEntry; +import org.apache.sshd.common.util.io.ModifiableFileWatcher; +import org.eclipse.jgit.util.IO; + +/** + * An implementation of an OpenSSH key revocation list (KRL), either a binary + * KRL or a simple list of public keys. + */ +class OpenSshKrl extends ModifiableFileWatcher { + + private static record State(Set<String> keys, OpenSshBinaryKrl krl) { + // Empty + } + + private State state; + + public OpenSshKrl(Path path) { + super(path); + state = new State(Set.of(), null); + } + + public boolean isRevoked(PublicKey key) throws IOException { + State current = refresh(); + return isRevoked(current, key); + } + + private boolean isRevoked(State current, PublicKey key) { + if (key instanceof OpenSshCertificate cert) { + OpenSshBinaryKrl krl = current.krl(); + if (krl != null && krl.isRevoked(cert)) { + return true; + } + if (isRevoked(current, cert.getCaPubKey()) + || isRevoked(current, cert.getCertPubKey())) { + return true; + } + return false; + } + OpenSshBinaryKrl krl = current.krl(); + if (krl != null) { + return krl.isRevoked(key); + } + return current.keys().contains(PublicKeyEntry.toString(key)); + } + + private synchronized State refresh() throws IOException { + if (checkReloadRequired()) { + updateReloadAttributes(); + try { + state = reload(getPath()); + } catch (NoSuchFileException e) { + // File disappeared + resetReloadAttributes(); + state = new State(Set.of(), null); + } + } + return state; + } + + private static State reload(Path path) throws IOException { + try (BufferedInputStream in = new BufferedInputStream( + Files.newInputStream(path))) { + byte[] magic = new byte[OpenSshBinaryKrl.MAGIC.length]; + in.mark(magic.length); + IO.readFully(in, magic); + if (Arrays.equals(magic, OpenSshBinaryKrl.MAGIC)) { + return new State(null, OpenSshBinaryKrl.load(in, true)); + } + // Otherwise try reading it textually + in.reset(); + return loadTextKrl(in); + } + } + + private static State loadTextKrl(InputStream in) throws IOException { + Set<String> keys = new HashSet<>(); + try (BufferedReader r = new BufferedReader( + new InputStreamReader(in, StandardCharsets.UTF_8))) { + String line; + for (;;) { + line = r.readLine(); + if (line == null) { + break; + } + line = line.strip(); + if (line.isEmpty() || line.charAt(0) == '#') { + continue; + } + keys.add(AllowedSigners.parsePublicKey(line, 0)); + } + } + return new State(keys, null); + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshSigningKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshSigningKeyDatabase.java new file mode 100644 index 0000000..aa26886 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/OpenSshSigningKeyDatabase.java
@@ -0,0 +1,161 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.security.PublicKey; +import java.time.Instant; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.lib.GpgConfig; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.signing.ssh.CachingSigningKeyDatabase; +import org.eclipse.jgit.signing.ssh.VerificationException; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.StringUtils; + +/** + * A {@link CachingSigningKeyDatabase} using the OpenSSH allowed signers file + * and the OpenSSH key revocation list. + */ +public class OpenSshSigningKeyDatabase implements CachingSigningKeyDatabase { + + // Keep caches of allowed signers and KRLs. Cache by canonical path. + + private static final int DEFAULT_CACHE_SIZE = 5; + + private AtomicInteger cacheSize = new AtomicInteger(DEFAULT_CACHE_SIZE); + + private class LRU<K, V> extends LinkedHashMap<K, V> { + + private static final long serialVersionUID = 1L; + + LRU() { + super(DEFAULT_CACHE_SIZE, 0.75f, true); + } + + @Override + protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) { + return size() > cacheSize.get(); + } + } + + private final HashMap<Path, AllowedSigners> allowedSigners = new LRU<>(); + + private final HashMap<Path, OpenSshKrl> revocations = new LRU<>(); + + @Override + public boolean isRevoked(Repository repository, GpgConfig config, + PublicKey key) throws IOException { + String fileName = config.getSshRevocationFile(); + if (StringUtils.isEmptyOrNull(fileName)) { + return false; + } + File file = getFile(repository, fileName); + OpenSshKrl revocationList; + synchronized (revocations) { + revocationList = revocations.computeIfAbsent(file.toPath(), + OpenSshKrl::new); + } + return revocationList.isRevoked(key); + } + + @Override + public String isAllowed(Repository repository, GpgConfig config, + PublicKey key, String namespace, PersonIdent ident) + throws IOException, VerificationException { + String fileName = config.getSshAllowedSignersFile(); + if (StringUtils.isEmptyOrNull(fileName)) { + // No file configured. Git would error out. + return null; + } + File file = getFile(repository, fileName); + AllowedSigners allowed; + synchronized (allowedSigners) { + allowed = allowedSigners.computeIfAbsent(file.toPath(), + AllowedSigners::new); + } + Instant gitTime = null; + if (ident != null) { + gitTime = ident.getWhenAsInstant(); + } + return allowed.isAllowed(key, namespace, null, gitTime); + } + + private File getFile(@NonNull Repository repository, String fileName) + throws IOException { + File file; + if (fileName.startsWith("~/") //$NON-NLS-1$ + || fileName.startsWith('~' + File.separator)) { + file = FS.DETECTED.resolve(FS.DETECTED.userHome(), + fileName.substring(2)); + } else { + file = new File(fileName); + if (!file.isAbsolute()) { + file = new File(repository.getWorkTree(), fileName); + } + } + return file.getCanonicalFile(); + } + + @Override + public int getCacheSize() { + return cacheSize.get(); + } + + @Override + public void setCacheSize(int size) { + if (size > 0) { + cacheSize.set(size); + pruneCache(size); + } + } + + private void pruneCache(int size) { + prune(allowedSigners, size); + prune(revocations, size); + } + + private void prune(HashMap<?, ?> map, int size) { + synchronized (map) { + if (map.size() <= size) { + return; + } + Iterator<?> iter = map.entrySet().iterator(); + int i = 0; + while (iter.hasNext() && i < size) { + iter.next(); + i++; + } + while (iter.hasNext()) { + iter.next(); + iter.remove(); + } + } + } + + @Override + public void clearCache() { + synchronized (allowedSigners) { + allowedSigners.clear(); + } + synchronized (revocations) { + revocations.clear(); + } + } + +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java new file mode 100644 index 0000000..f4eb884 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java
@@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.util.TreeMap; + +import org.eclipse.jgit.internal.transport.sshd.SshdText; + +/** + * Encapsulates the storage for revoked certificate serial numbers. + */ +class SerialRangeSet { + + /** + * A range of certificate serial numbers [from..to], i.e., with both range + * limits included. + */ + private interface SerialRange { + + long from(); + + long to(); + } + + private static record Singleton(long from) implements SerialRange { + + @Override + public long to() { + return from; + } + } + + private static record Range(long from, long to) implements SerialRange { + + public Range(long from, long to) { + if (Long.compareUnsigned(from, to) > 0) { + throw new IllegalArgumentException( + SshdText.get().signKrlEmptyRange); + } + this.from = from; + this.to = to; + } + } + + // We use the same data structure as OpenSSH; basically a TreeSet of mutable + // SerialRanges. To get "mutability", the set is implemented as a TreeMap + // with the same elements as keys and values. + // + // get(x) will return null if none of the serial numbers in the range x is + // in the set, and some range (partially) overlapping with x otherwise. + // + // containsKey(x) will return true if there is any (partially) overlapping + // range in the TreeMap. + private final TreeMap<SerialRange, SerialRange> ranges = new TreeMap<>( + SerialRangeSet::compare); + + private static int compare(SerialRange a, SerialRange b) { + // Return == if they overlap + if (Long.compareUnsigned(a.to(), b.from()) >= 0 + && Long.compareUnsigned(a.from(), b.to()) <= 0) { + return 0; + } + return Long.compareUnsigned(a.from(), b.from()); + } + + void add(long serial) { + add(ranges, new Singleton(serial)); + } + + void add(long from, long to) { + add(ranges, new Range(from, to)); + } + + boolean contains(long serial) { + return ranges.containsKey(new Singleton(serial)); + } + + int size() { + return ranges.size(); + } + + boolean isEmpty() { + return ranges.isEmpty(); + } + + private static void add(TreeMap<SerialRange, SerialRange> ranges, + SerialRange newRange) { + for (;;) { + SerialRange existing = ranges.get(newRange); + if (existing == null) { + break; + } + if (Long.compareUnsigned(existing.from(), newRange.from()) <= 0 + && Long.compareUnsigned(existing.to(), + newRange.to()) >= 0) { + // newRange completely contained in existing + return; + } + ranges.remove(existing); + long newFrom = newRange.from(); + if (Long.compareUnsigned(existing.from(), newFrom) < 0) { + newFrom = existing.from(); + } + long newTo = newRange.to(); + if (Long.compareUnsigned(existing.to(), newTo) > 0) { + newTo = existing.to(); + } + newRange = new Range(newFrom, newTo); + } + // No overlapping range exists: check for coalescing with the + // previous/next range + SerialRange prev = ranges.floorKey(newRange); + if (prev != null && newRange.from() - prev.to() == 1) { + ranges.remove(prev); + newRange = new Range(prev.from(), newRange.to()); + } + SerialRange next = ranges.ceilingKey(newRange); + if (next != null && next.from() - newRange.to() == 1) { + ranges.remove(next); + newRange = new Range(newRange.from(), next.to()); + } + ranges.put(newRange, newRange); + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SigningDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SigningDatabase.java new file mode 100644 index 0000000..e2e1a36 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SigningDatabase.java
@@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import org.eclipse.jgit.signing.ssh.CachingSigningKeyDatabase; +import org.eclipse.jgit.signing.ssh.SigningKeyDatabase; + +/** + * A global {@link SigningKeyDatabase} instance. + */ +public final class SigningDatabase { + + private static SigningKeyDatabase INSTANCE = new OpenSshSigningKeyDatabase(); + + private SigningDatabase() { + // No instantiation + } + + /** + * Obtains the current instance. + * + * @return the global {@link SigningKeyDatabase} + */ + public static synchronized SigningKeyDatabase getInstance() { + return INSTANCE; + } + + /** + * Sets the global {@link SigningKeyDatabase}. + * + * @param database + * to set; if {@code null} a default database using the OpenSSH + * allowed signers file and the OpenSSH revocation list mechanism + * is used. + * @return the previously set {@link SigningKeyDatabase} + */ + public static synchronized SigningKeyDatabase setInstance( + SigningKeyDatabase database) { + SigningKeyDatabase previous = INSTANCE; + if (database != INSTANCE) { + if (INSTANCE instanceof CachingSigningKeyDatabase caching) { + caching.clearCache(); + } + if (database == null) { + INSTANCE = new OpenSshSigningKeyDatabase(); + } else { + INSTANCE = database; + } + } + return previous; + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshCertificateUtils.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshCertificateUtils.java new file mode 100644 index 0000000..040c6d4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshCertificateUtils.java
@@ -0,0 +1,175 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.security.PublicKey; +import java.text.MessageFormat; +import java.time.Instant; + +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.signature.BuiltinSignatures; +import org.apache.sshd.common.signature.Signature; +import org.apache.sshd.common.util.buffer.Buffer; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.internal.transport.sshd.SshdText; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility methods for working with OpenSSH certificates. + */ +final class SshCertificateUtils { + + private static final Logger LOG = LoggerFactory + .getLogger(SshCertificateUtils.class); + + /** + * Verifies a certificate: checks that it is a user certificate and has a + * valid signature, and if a time is given, that the certificate is valid at + * that time. + * + * @param certificate + * {@link OpenSshCertificate} to verify + * @param signatureTime + * {@link Instant} to check whether the certificate is valid at + * that time; maybe {@code null}, in which case the valid-time + * check is skipped. + * @return {@code null} if the certificate is valid; otherwise a descriptive + * message + */ + static String verify(OpenSshCertificate certificate, + Instant signatureTime) { + if (!OpenSshCertificate.Type.USER.equals(certificate.getType())) { + return MessageFormat.format(SshdText.get().signNotUserCertificate, + KeyUtils.getFingerPrint(certificate.getCaPubKey())); + } + String message = verifySignature(certificate); + if (message == null && signatureTime != null) { + message = checkExpiration(certificate, signatureTime); + } + return message; + } + + /** + * Verifies the signature on a certificate. + * + * @param certificate + * {@link OpenSshCertificate} to verify + * @return {@code null} if the signature is valid; otherwise a descriptive + * message + */ + static String verifySignature(OpenSshCertificate certificate) { + // Verify the signature on the certificate. + // + // Note that OpenSSH certificates do not support chaining. + // + // ssh-keygen refuses to create a certificate for a certificate, so the + // certified key cannot be another OpenSshCertificate. Additionally, + // when creating a certificate ssh-keygen loads the CA private key to + // make the signature and reconstructs the public key that it stores in + // the certificate from that, so the CA public key also cannot be an + // OpenSshCertificate. + PublicKey caKey = certificate.getCaPubKey(); + PublicKey certifiedKey = certificate.getCertPubKey(); + if (caKey == null + || caKey instanceof OpenSshCertificate + || certifiedKey == null + || certifiedKey instanceof OpenSshCertificate) { + return SshdText.get().signCertificateInvalid; + } + // Verify that key type and algorithm match + String keyType = KeyUtils.getKeyType(caKey); + String certAlgorithm = certificate.getSignatureAlgorithm(); + if (!KeyUtils.getCanonicalKeyType(keyType) + .equals(KeyUtils.getCanonicalKeyType(certAlgorithm))) { + return MessageFormat.format( + SshdText.get().signCertAlgorithmMismatch, keyType, + KeyUtils.getFingerPrint(certificate.getCaPubKey()), + certAlgorithm); + } + BuiltinSignatures factory = BuiltinSignatures + .fromFactoryName(certAlgorithm); + if (factory == null || !factory.isSupported()) { + return MessageFormat.format(SshdText.get().signCertAlgorithmUnknown, + KeyUtils.getFingerPrint(certificate.getCaPubKey()), + certAlgorithm); + } + Signature signer = factory.create(); + try { + signer.initVerifier(null, caKey); + signer.update(null, getBlob(certificate)); + if (signer.verify(null, certificate.getRawSignature())) { + return null; + } + } catch (Exception e) { + LOG.warn("{}", SshdText.get().signLogFailure, e); //$NON-NLS-1$ + return SshdText.get().signSeeLog; + } + return MessageFormat.format(SshdText.get().signCertificateInvalid, + KeyUtils.getFingerPrint(certificate.getCaPubKey())); + } + + private static byte[] getBlob(OpenSshCertificate certificate) { + // Theoretically, this should be just certificate.getMessage(). But + // Apache MINA sshd has a bug and may return additional bytes if the + // certificate is not the first thing in the buffer it was read from. + // As a work-around, re-create the signed blob from scratch. + // + // This may be replaced by return certificate.getMessage() once the + // upstream bug is fixed. + // + // See https://github.com/apache/mina-sshd/issues/618 + Buffer tmp = new ByteArrayBuffer(); + tmp.putString(certificate.getKeyType()); + tmp.putBytes(certificate.getNonce()); + tmp.putRawPublicKeyBytes(certificate.getCertPubKey()); + tmp.putLong(certificate.getSerial()); + tmp.putInt(certificate.getType().getCode()); + tmp.putString(certificate.getId()); + Buffer list = new ByteArrayBuffer(); + list.putStringList(certificate.getPrincipals(), false); + tmp.putBytes(list.getCompactData()); + tmp.putLong(certificate.getValidAfter()); + tmp.putLong(certificate.getValidBefore()); + tmp.putCertificateOptions(certificate.getCriticalOptions()); + tmp.putCertificateOptions(certificate.getExtensions()); + tmp.putString(certificate.getReserved()); + Buffer inner = new ByteArrayBuffer(); + inner.putRawPublicKey(certificate.getCaPubKey()); + tmp.putBytes(inner.getCompactData()); + return tmp.getCompactData(); + } + + /** + * Checks whether a certificate is valid at a given time. + * + * @param certificate + * {@link OpenSshCertificate} to check + * @param signatureTime + * {@link Instant} to check + * @return {@code null} if the certificate is valid at the given instant; + * otherwise a descriptive message + */ + static String checkExpiration(OpenSshCertificate certificate, + @NonNull Instant signatureTime) { + long instant = signatureTime.getEpochSecond(); + if (Long.compareUnsigned(instant, certificate.getValidAfter()) < 0) { + return MessageFormat.format(SshdText.get().signCertificateTooEarly, + KeyUtils.getFingerPrint(certificate.getCaPubKey())); + } else if (Long.compareUnsigned(instant, + certificate.getValidBefore()) > 0) { + return MessageFormat.format(SshdText.get().signCertificateExpired, + KeyUtils.getFingerPrint(certificate.getCaPubKey())); + } + return null; + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSignatureConstants.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSignatureConstants.java new file mode 100644 index 0000000..bc72196 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSignatureConstants.java
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.nio.charset.StandardCharsets; + +import org.eclipse.jgit.lib.Constants; + +/** + * Defines common constants for SSH signatures. + */ +final class SshSignatureConstants { + + private static final String SIGNATURE_END = "-----END SSH SIGNATURE-----"; //$NON-NLS-1$ + + static final byte[] MAGIC = { 'S', 'S', 'H', 'S', 'I', 'G' }; + + static final int VERSION = 1; + + static final String NAMESPACE = "git"; //$NON-NLS-1$ + + static final byte[] ARMOR_HEAD = Constants.SSH_SIGNATURE_PREFIX + .getBytes(StandardCharsets.US_ASCII); + + static final byte[] ARMOR_END = SIGNATURE_END + .getBytes(StandardCharsets.US_ASCII); + + private SshSignatureConstants() { + // No instantiation + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSignatureVerifier.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSignatureVerifier.java new file mode 100644 index 0000000..76be340 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSignatureVerifier.java
@@ -0,0 +1,319 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.text.MessageFormat; +import java.time.Instant; +import java.util.Date; +import java.util.Locale; + +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.signature.BuiltinSignatures; +import org.apache.sshd.common.signature.Signature; +import org.apache.sshd.common.util.buffer.Buffer; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.eclipse.jgit.internal.transport.sshd.SshdText; +import org.eclipse.jgit.lib.GpgConfig; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifier; +import org.eclipse.jgit.signing.ssh.CachingSigningKeyDatabase; +import org.eclipse.jgit.signing.ssh.SigningKeyDatabase; +import org.eclipse.jgit.signing.ssh.VerificationException; +import org.eclipse.jgit.util.Base64; +import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link SignatureVerifier} for SSH signatures. + */ +public class SshSignatureVerifier implements SignatureVerifier { + + private static final Logger LOG = LoggerFactory + .getLogger(SshSignatureVerifier.class); + + private static final byte[] OBJECT = { 'o', 'b', 'j', 'e', 'c', 't', ' ' }; + + private static final byte[] TREE = { 't', 'r', 'e', 'e', ' ' }; + + private static final byte[] TYPE = { 't', 'y', 'p', 'e', ' ' }; + + @Override + public String getName() { + return "ssh"; //$NON-NLS-1$ + } + + @Override + public SignatureVerification verify(Repository repository, GpgConfig config, + byte[] data, byte[] signatureData) throws IOException { + // This is a bit stupid. SSH signatures do not store a signer, nor a + // time the signature was created. So we must use the committer's or + // tagger's PersonIdent, but here we have neither. But... if we see + // that the data is a commit or tag, then we can parse the PersonIdent + // from the data. + // + // Note: we cannot assume that absent a principal recorded in the + // allowedSignersFile or on a certificate that the key used to sign the + // commit belonged to the committer. + PersonIdent gitIdentity = getGitIdentity(data); + Date signatureDate = null; + Instant signatureInstant = null; + if (gitIdentity != null) { + signatureDate = gitIdentity.getWhen(); + signatureInstant = gitIdentity.getWhenAsInstant(); + } + + TrustLevel trust = TrustLevel.NEVER; + byte[] decodedSignature; + try { + decodedSignature = dearmor(signatureData); + } catch (IllegalArgumentException e) { + return new SignatureVerification(getName(), signatureDate, null, + null, null, false, false, trust, + MessageFormat.format(SshdText.get().signInvalidSignature, + e.getLocalizedMessage())); + } + int start = RawParseUtils.match(decodedSignature, 0, + SshSignatureConstants.MAGIC); + if (start < 0) { + return new SignatureVerification(getName(), signatureDate, null, + null, null, false, false, trust, + SshdText.get().signInvalidMagic); + } + ByteArrayBuffer signature = new ByteArrayBuffer(decodedSignature, start, + decodedSignature.length - start); + + long version = signature.getUInt(); + if (version != SshSignatureConstants.VERSION) { + return new SignatureVerification(getName(), signatureDate, null, + null, null, false, false, trust, + MessageFormat.format(SshdText.get().signInvalidVersion, + Long.toString(version))); + } + + PublicKey key = signature.getPublicKey(); + String fingerprint; + if (key instanceof OpenSshCertificate cert) { + fingerprint = KeyUtils.getFingerPrint(cert.getCertPubKey()); + String message = SshCertificateUtils.verify(cert, signatureInstant); + if (message != null) { + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, message); + } + } else { + fingerprint = KeyUtils.getFingerPrint(key); + } + + String namespace = signature.getString(); + if (!SshSignatureConstants.NAMESPACE.equals(namespace)) { + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, + MessageFormat.format(SshdText.get().signInvalidNamespace, + namespace)); + } + + signature.getString(); // Skip the reserved field + String hashAlgorithm = signature.getString(); + byte[] hash; + try { + hash = MessageDigest + .getInstance(hashAlgorithm.toUpperCase(Locale.ROOT)) + .digest(data); + } catch (NoSuchAlgorithmException e) { + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, + MessageFormat.format( + SshdText.get().signUnknownHashAlgorithm, + hashAlgorithm)); + } + ByteArrayBuffer rawSignature = new ByteArrayBuffer( + signature.getBytes()); + if (signature.available() > 0) { + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, + SshdText.get().signGarbageAtEnd); + } + + String signatureAlgorithm = rawSignature.getString(); + switch (signatureAlgorithm) { + case KeyPairProvider.SSH_DSS: + case KeyPairProvider.SSH_DSS_CERT: + case KeyPairProvider.SSH_RSA: + case KeyPairProvider.SSH_RSA_CERT: + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, + MessageFormat.format(SshdText.get().signInvalidAlgorithm, + signatureAlgorithm)); + } + + String keyType = KeyUtils + .getSignatureAlgorithm(KeyUtils.getKeyType(key), key); + if (!KeyUtils.getCanonicalKeyType(keyType) + .equals(KeyUtils.getCanonicalKeyType(signatureAlgorithm))) { + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, + MessageFormat.format( + SshdText.get().signMismatchedSignatureAlgorithm, + keyType, signatureAlgorithm)); + } + + BuiltinSignatures factory = BuiltinSignatures + .fromFactoryName(signatureAlgorithm); + if (factory == null || !factory.isSupported()) { + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, null, false, false, trust, + MessageFormat.format( + SshdText.get().signUnknownSignatureAlgorithm, + signatureAlgorithm)); + } + + boolean valid; + String message = null; + try { + Signature verifier = factory.create(); + verifier.initVerifier(null, + key instanceof OpenSshCertificate cert + ? cert.getCertPubKey() + : key); + // Feed it the data + Buffer toSign = new ByteArrayBuffer(); + toSign.putRawBytes(SshSignatureConstants.MAGIC); + toSign.putString(SshSignatureConstants.NAMESPACE); + toSign.putUInt(0); // reserved: zero-length string + toSign.putString(hashAlgorithm); + toSign.putBytes(hash); + verifier.update(null, toSign.getCompactData()); + valid = verifier.verify(null, rawSignature.getBytes()); + } catch (Exception e) { + LOG.warn("{}", SshdText.get().signLogFailure, e); //$NON-NLS-1$ + valid = false; + message = SshdText.get().signSeeLog; + } + boolean expired = false; + String principal = null; + if (valid) { + if (rawSignature.available() > 0) { + valid = false; + message = SshdText.get().signGarbageAtEnd; + } else { + SigningKeyDatabase database = SigningKeyDatabase.getInstance(); + if (database.isRevoked(repository, config, key)) { + valid = false; + if (key instanceof OpenSshCertificate certificate) { + message = MessageFormat.format( + SshdText.get().signCertificateRevoked, + KeyUtils.getFingerPrint( + certificate.getCaPubKey())); + } else { + message = SshdText.get().signKeyRevoked; + } + } else { + // This may turn a positive verification into a failed one. + try { + principal = database.isAllowed(repository, config, key, + SshSignatureConstants.NAMESPACE, gitIdentity); + if (!StringUtils.isEmptyOrNull(principal)) { + trust = TrustLevel.FULL; + } else { + valid = false; + message = SshdText.get().signNoPrincipalMatched; + trust = TrustLevel.UNKNOWN; + } + } catch (VerificationException e) { + valid = false; + message = e.getMessage(); + expired = e.isExpired(); + } catch (IOException e) { + LOG.warn("{}", SshdText.get().signLogFailure, e); //$NON-NLS-1$ + valid = false; + message = SshdText.get().signSeeLog; + } + } + } + } + return new SignatureVerification(getName(), signatureDate, null, + fingerprint, principal, valid, expired, trust, message); + } + + private static PersonIdent getGitIdentity(byte[] rawObject) { + // Data from a commit will start with "tree ID\n". + int i = RawParseUtils.match(rawObject, 0, TREE); + if (i > 0) { + i = RawParseUtils.committer(rawObject, 0); + if (i < 0) { + return null; + } + return RawParseUtils.parsePersonIdent(rawObject, i); + } + // Data from a tag will start with "object ID\ntype ". + i = RawParseUtils.match(rawObject, 0, OBJECT); + if (i > 0) { + i = RawParseUtils.nextLF(rawObject, i); + i = RawParseUtils.match(rawObject, i, TYPE); + if (i > 0) { + i = RawParseUtils.tagger(rawObject, 0); + if (i < 0) { + return null; + } + return RawParseUtils.parsePersonIdent(rawObject, i); + } + } + return null; + } + + private static byte[] dearmor(byte[] data) { + int start = RawParseUtils.match(data, 0, + SshSignatureConstants.ARMOR_HEAD); + if (start > 0) { + if (data[start] == '\r') { + start++; + } + if (data[start] == '\n') { + start++; + } + } + int end = data.length; + if (end > start + 1 && data[end - 1] == '\n') { + end--; + if (end > start + 1 && data[end - 1] == '\r') { + end--; + } + } + end = end - SshSignatureConstants.ARMOR_END.length; + if (end >= 0 && end >= start + && RawParseUtils.match(data, end, + SshSignatureConstants.ARMOR_END) >= 0) { + // end is fine: on the first the character of the end marker + } else { + // No end marker. + end = data.length; + } + if (start < 0) { + start = 0; + } + return Base64.decode(data, start, end - start); + } + + @Override + public void clear() { + SigningKeyDatabase database = SigningKeyDatabase.getInstance(); + if (database instanceof CachingSigningKeyDatabase caching) { + caching.clearCache(); + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSigner.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSigner.java new file mode 100644 index 0000000..8cfe5f4 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SshSigner.java
@@ -0,0 +1,485 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.signing.ssh; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StreamCorruptedException; +import java.io.StringReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.text.MessageFormat; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity; +import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.OpenSshCertificate; +import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; +import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.session.SessionContext; +import org.apache.sshd.common.signature.BuiltinSignatures; +import org.apache.sshd.common.signature.Signature; +import org.apache.sshd.common.util.buffer.Buffer; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.errors.CanceledException; +import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException; +import org.eclipse.jgit.internal.transport.sshd.AuthenticationCanceledException; +import org.eclipse.jgit.internal.transport.sshd.PasswordProviderWrapper; +import org.eclipse.jgit.internal.transport.sshd.SshdText; +import org.eclipse.jgit.internal.transport.sshd.agent.SshAgentClient; +import org.eclipse.jgit.lib.GpgConfig; +import org.eclipse.jgit.lib.GpgSignature; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.Signer; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.sshd.KeyPasswordProviderFactory; +import org.eclipse.jgit.transport.sshd.agent.Connector; +import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory; +import org.eclipse.jgit.util.Base64; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FS.ExecutionResult; +import org.eclipse.jgit.util.StringUtils; +import org.eclipse.jgit.util.SystemReader; +import org.eclipse.jgit.util.TemporaryBuffer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link Signer} to create SSH signatures. + * + * @see <a href= + * "https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig">PROTOCOL.sshsig</a> + */ +public class SshSigner implements Signer { + + private static final Logger LOG = LoggerFactory.getLogger(SshSigner.class); + + private static final String GIT_KEY_PREFIX = "key::"; //$NON-NLS-1$ + + // Base64 encoded lines should not be longer than 75 characters, plus the + // newline. + private static final int LINE_LENGTH = 75; + + @Override + public GpgSignature sign(Repository repository, GpgConfig config, + byte[] data, PersonIdent committer, String signingKey, + CredentialsProvider credentialsProvider) throws CanceledException, + IOException, UnsupportedSigningFormatException { + byte[] hash; + try { + hash = MessageDigest.getInstance("SHA512").digest(data); //$NON-NLS-1$ + } catch (NoSuchAlgorithmException e) { + throw new UnsupportedSigningFormatException( + MessageFormat.format( + SshdText.get().signUnknownHashAlgorithm, "SHA512"), //$NON-NLS-1$ + e); + } + Buffer toSign = new ByteArrayBuffer(); + toSign.putRawBytes(SshSignatureConstants.MAGIC); + toSign.putString(SshSignatureConstants.NAMESPACE); + toSign.putUInt(0); // reserved: zero-length string + toSign.putString("sha512"); //$NON-NLS-1$ + toSign.putBytes(hash); + String key = signingKey; + if (StringUtils.isEmptyOrNull(key)) { + key = config.getSigningKey(); + } + if (StringUtils.isEmptyOrNull(key)) { + key = defaultKeyCommand(repository, config); + // According to documentation, this is supposed to return a + // valid SSH public key prefixed with "key::". We don't enforce + // this: there might be older command implementations (like just + // calling "ssh-add -L") that return keys without prefix. + } + PublicKeyIdentity identity; + try { + identity = getIdentity(key, committer, credentialsProvider); + } catch (GeneralSecurityException e) { + throw new UnsupportedSigningFormatException(MessageFormat + .format(SshdText.get().signPublicKeyError, key), e); + } + String algorithm = KeyUtils + .getKeyType(identity.getKeyIdentity().getPublic()); + switch (algorithm) { + case KeyPairProvider.SSH_DSS: + case KeyPairProvider.SSH_DSS_CERT: + throw new UnsupportedSigningFormatException( + SshdText.get().signInvalidKeyDSA); + case KeyPairProvider.SSH_RSA: + algorithm = KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS; + break; + case KeyPairProvider.SSH_RSA_CERT: + algorithm = KeyUtils.RSA_SHA512_CERT_TYPE_ALIAS; + break; + default: + break; + } + + Map.Entry<String, byte[]> rawSignature; + try { + rawSignature = identity.sign(null, algorithm, + toSign.getCompactData()); + } catch (Exception e) { + throw new UnsupportedSigningFormatException( + SshdText.get().signSignatureError, e); + } + algorithm = rawSignature.getKey(); + Buffer signature = new ByteArrayBuffer(); + signature.putRawBytes(SshSignatureConstants.MAGIC); + signature.putUInt(SshSignatureConstants.VERSION); + signature.putPublicKey(identity.getKeyIdentity().getPublic()); + signature.putString(SshSignatureConstants.NAMESPACE); + signature.putUInt(0); // reserved: zero-length string + signature.putString("sha512"); //$NON-NLS-1$ + Buffer sig = new ByteArrayBuffer(); + sig.putString(KeyUtils.getSignatureAlgorithm(algorithm, + identity.getKeyIdentity().getPublic())); + sig.putBytes(rawSignature.getValue()); + signature.putBytes(sig.getCompactData()); + return armor(signature.getCompactData()); + } + + private static String defaultKeyCommand(@NonNull Repository repository, + @NonNull GpgConfig config) throws IOException { + String command = config.getSshDefaultKeyCommand(); + if (StringUtils.isEmptyOrNull(command)) { + return null; + } + FS fileSystem = repository.getFS(); + if (fileSystem == null) { + fileSystem = FS.DETECTED; + } + ProcessBuilder builder = fileSystem.runInShell(command, + new String[] {}); + ExecutionResult result = null; + try { + result = fileSystem.execute(builder, null); + int exitCode = result.getRc(); + if (exitCode == 0) { + // The command is supposed to return a public key in its first + // line on stdout. + try (BufferedReader r = new BufferedReader( + new InputStreamReader( + result.getStdout().openInputStream(), + SystemReader.getInstance() + .getDefaultCharset()))) { + String line = r.readLine(); + if (line != null) { + line = line.strip(); + } + if (StringUtils.isEmptyOrNull(line)) { + throw new IOException(MessageFormat.format( + SshdText.get().signDefaultKeyEmpty, command)); + } + return line; + } + } + TemporaryBuffer stderr = result.getStderr(); + throw new IOException(MessageFormat.format( + SshdText.get().signDefaultKeyFailed, command, + Integer.toString(exitCode), toString(stderr))); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException( + MessageFormat.format( + SshdText.get().signDefaultKeyInterrupted, command), + e); + } finally { + if (result != null) { + if (result.getStderr() != null) { + result.getStderr().destroy(); + } + if (result.getStdout() != null) { + result.getStdout().destroy(); + } + } + } + } + + private static String toString(TemporaryBuffer b) { + if (b != null) { + try { + return new String(b.toByteArray(4000), + SystemReader.getInstance().getDefaultCharset()); + } catch (IOException e) { + LOG.warn("{}", SshdText.get().signStderr, e); //$NON-NLS-1$ + } + } + return ""; //$NON-NLS-1$ + } + + private static PublicKeyIdentity getIdentity(String signingKey, + PersonIdent committer, CredentialsProvider credentials) + throws CanceledException, GeneralSecurityException, IOException { + if (StringUtils.isEmptyOrNull(signingKey)) { + throw new IllegalArgumentException(SshdText.get().signNoSigningKey); + } + PublicKey publicKey = null; + PrivateKey privateKey = null; + File keyFile = null; + if (signingKey.startsWith(GIT_KEY_PREFIX)) { + try (StringReader r = new StringReader( + signingKey.substring(GIT_KEY_PREFIX.length()))) { + publicKey = fromEntry( + AuthorizedKeyEntry.readAuthorizedKeys(r, true)); + } + } else if (signingKey.startsWith("~/") //$NON-NLS-1$ + || signingKey.startsWith('~' + File.separator)) { + keyFile = new File(FS.DETECTED.userHome(), signingKey.substring(2)); + } else { + try (StringReader r = new StringReader(signingKey)) { + publicKey = fromEntry( + AuthorizedKeyEntry.readAuthorizedKeys(r, true)); + } catch (IOException e) { + // Ignore and try to read as a file + keyFile = new File(signingKey); + } + } + if (keyFile != null && keyFile.isFile()) { + try { + publicKey = fromEntry(AuthorizedKeyEntry + .readAuthorizedKeys(keyFile.toPath())); + if (publicKey == null) { + throw new IOException(MessageFormat.format( + SshdText.get().signTooManyPublicKeys, keyFile)); + } + // Try to find the private key so we don't go looking for + // the agent (or PKCS#11) in vain. + keyFile = getPrivateKeyFile(keyFile.getParentFile(), + keyFile.getName()); + if (keyFile != null) { + try { + KeyPair pair = loadPrivateKey(keyFile.toPath(), + credentials); + if (pair != null) { + PublicKey pk = pair.getPublic(); + if (pk == null) { + privateKey = pair.getPrivate(); + } else { + PublicKey original = publicKey; + if (publicKey instanceof OpenSshCertificate cert) { + original = cert.getCertPubKey(); + } + if (KeyUtils.compareKeys(original, pk)) { + privateKey = pair.getPrivate(); + } + } + } + } catch (IOException e) { + // Apparently it wasn't a private key file. Ignore. + } + } + } catch (StreamCorruptedException e) { + // File is readable, but apparently not a public key. Try to + // load it as a private key. + KeyPair pair = loadPrivateKey(keyFile.toPath(), credentials); + if (pair != null) { + publicKey = pair.getPublic(); + privateKey = pair.getPrivate(); + } + } + } + if (publicKey == null) { + throw new IOException(MessageFormat + .format(SshdText.get().signNoPublicKey, signingKey)); + } + if (publicKey instanceof OpenSshCertificate cert) { + String message = SshCertificateUtils.verify(cert, + committer.getWhenAsInstant()); + if (message != null) { + throw new IOException(message); + } + } + if (privateKey == null) { + // Could be in the agent, or a PKCS#11 key. The normal procedure + // with PKCS#11 keys is to put them in the agent and let the agent + // deal with it. + // + // This may or may not work well. For instance, the agent might ask + // for a passphrase for PKCS#11 keys... also, the OpenSSH ssh-agent + // had a bug with signing using PKCS#11 certificates in the agent; + // see https://bugzilla.mindrot.org/show_bug.cgi?id=3613 . If there + // are troubles, we might do the PKCS#11 dance ourselves, but we'd + // need additional configuration for the PKCS#11 library. (Plus + // some refactoring in the Pkcs11Provider.) + return new AgentIdentity(publicKey); + + } + return new KeyPairIdentity(new KeyPair(publicKey, privateKey)); + } + + private static File getPrivateKeyFile(File directory, + String publicKeyName) { + if (publicKeyName.endsWith(".pub")) { //$NON-NLS-1$ + String privateKeyName = publicKeyName.substring(0, + publicKeyName.length() - 4); + if (!privateKeyName.isEmpty()) { + File keyFile = new File(directory, privateKeyName); + if (keyFile.isFile()) { + return keyFile; + } + if (privateKeyName.endsWith("-cert")) { //$NON-NLS-1$ + privateKeyName = privateKeyName.substring(0, + privateKeyName.length() - 5); + if (!privateKeyName.isEmpty()) { + keyFile = new File(directory, privateKeyName); + if (keyFile.isFile()) { + return keyFile; + } + } + } + } + } + return null; + } + + private static KeyPair loadPrivateKey(Path path, + CredentialsProvider credentials) + throws CanceledException, GeneralSecurityException, IOException { + if (!Files.isRegularFile(path)) { + return null; + } + KeyPairResourceParser parser = SecurityUtils.getKeyPairResourceParser(); + if (parser != null) { + PasswordProviderWrapper provider = null; + if (credentials != null) { + provider = new PasswordProviderWrapper( + () -> KeyPasswordProviderFactory.getInstance() + .apply(credentials)); + } + try { + Collection<KeyPair> keyPairs = parser.loadKeyPairs(null, path, + provider); + if (keyPairs.size() != 1) { + throw new GeneralSecurityException(MessageFormat.format( + SshdText.get().signTooManyPrivateKeys, path)); + } + return keyPairs.iterator().next(); + } catch (AuthenticationCanceledException e) { + throw new CanceledException(e.getMessage()); + } + } + return null; + } + + private static GpgSignature armor(byte[] data) throws IOException { + try (ByteArrayOutputStream b = new ByteArrayOutputStream()) { + b.write(SshSignatureConstants.ARMOR_HEAD); + b.write('\n'); + String encoded = Base64.encodeBytes(data); + int length = encoded.length(); + int column = 0; + for (int i = 0; i < length; i++) { + b.write(encoded.charAt(i)); + column++; + if (column == LINE_LENGTH) { + b.write('\n'); + column = 0; + } + } + if (column > 0) { + b.write('\n'); + } + b.write(SshSignatureConstants.ARMOR_END); + b.write('\n'); + return new GpgSignature(b.toByteArray()); + } + } + + private static PublicKey fromEntry(List<AuthorizedKeyEntry> entries) + throws GeneralSecurityException, IOException { + if (entries == null || entries.size() != 1) { + return null; + } + return entries.get(0).resolvePublicKey(null, + PublicKeyEntryResolver.FAILING); + } + + @Override + public boolean canLocateSigningKey(Repository repository, GpgConfig config, + PersonIdent committer, String signingKey, + CredentialsProvider credentialsProvider) throws CanceledException { + String key = signingKey; + if (key == null) { + key = config.getSigningKey(); + } + return !(StringUtils.isEmptyOrNull(key) + && StringUtils.isEmptyOrNull(config.getSshDefaultKeyCommand())); + } + + private static class KeyPairIdentity implements PublicKeyIdentity { + + private final @NonNull KeyPair pair; + + KeyPairIdentity(@NonNull KeyPair pair) { + this.pair = pair; + } + + @Override + public KeyPair getKeyIdentity() { + return pair; + } + + @Override + public Entry<String, byte[]> sign(SessionContext session, String algo, + byte[] data) throws Exception { + BuiltinSignatures factory = BuiltinSignatures.fromFactoryName(algo); + if (factory == null || !factory.isSupported()) { + throw new GeneralSecurityException(MessageFormat.format( + SshdText.get().signUnknownSignatureAlgorithm, algo)); + } + Signature signer = factory.create(); + signer.initSigner(null, pair.getPrivate()); + signer.update(null, data); + return new SimpleImmutableEntry<>(factory.getName(), + signer.sign(null)); + } + } + + private static class AgentIdentity extends KeyPairIdentity { + + AgentIdentity(PublicKey publicKey) { + super(new KeyPair(publicKey, null)); + } + + @Override + public Entry<String, byte[]> sign(SessionContext session, String algo, + byte[] data) throws Exception { + ConnectorFactory factory = ConnectorFactory.getDefault(); + Connector connector = factory == null ? null + : factory.create("", null); //$NON-NLS-1$ + if (connector == null) { + throw new IOException(SshdText.get().signNoAgent); + } + try (SshAgentClient agent = new SshAgentClient(connector)) { + return agent.sign(null, getKeyIdentity().getPublic(), algo, + data); + } + } + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java index b0b1028..6aace47 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
@@ -17,6 +17,7 @@ import java.io.File; import java.io.IOException; +import java.io.StreamCorruptedException; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -355,20 +356,20 @@ private PublicKey readPublicKey(String keyFile, boolean isDerived) { // only warn about non-existing files in case the key file is // not derived if (!isDerived) { - log.warn("{}", //$NON-NLS-1$ + log.warn(LOG_FORMAT, format(SshdText.get().cannotReadPublicKey, keyFile)); } - } catch (InvalidPathException | IOException e) { - log.warn("{}", //$NON-NLS-1$ - format(SshdText.get().cannotReadPublicKey, keyFile), e); - } catch (GeneralSecurityException e) { + } catch (GeneralSecurityException | StreamCorruptedException e) { // ignore in case this is not a derived key path, as in most // cases this specifies a private key if (isDerived) { - log.warn("{}", //$NON-NLS-1$ + log.warn(LOG_FORMAT, format(SshdText.get().cannotReadPublicKey, keyFile), e); } + } catch (InvalidPathException | IOException e) { + log.warn(LOG_FORMAT, + format(SshdText.get().cannotReadPublicKey, keyFile), e); } return null; }
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java index 96829b7..6b2345d 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/KnownHostEntryReader.java
@@ -29,6 +29,7 @@ import org.apache.sshd.client.config.hosts.KnownHostEntry; import org.apache.sshd.client.config.hosts.KnownHostHashValue; import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.apache.sshd.common.config.keys.PublicKeyEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,7 +98,7 @@ private static String clean(String line) { return i < 0 ? line.trim() : line.substring(0, i).trim(); } - private static KnownHostEntry parseHostEntry(String line) { + static KnownHostEntry parseHostEntry(String line) { KnownHostEntry entry = new KnownHostEntry(); entry.setConfigLine(line); String tmp = line; @@ -135,8 +136,8 @@ private static KnownHostEntry parseHostEntry(String line) { entry.setPatterns(patterns); } tmp = tmp.substring(i + 1).trim(); - AuthorizedKeyEntry key = AuthorizedKeyEntry - .parseAuthorizedKeyEntry(tmp); + AuthorizedKeyEntry key = PublicKeyEntry + .parsePublicKeyEntry(new AuthorizedKeyEntry(), tmp); if (key == null) { return null; }
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java index 2b4f7e5..acb77c5 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2018, 2025 Thomas Wolf <twolf@apache.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 @@ -31,9 +31,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; @@ -45,10 +47,13 @@ import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier.HostEntryPair; import org.apache.sshd.client.session.ClientSession; import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.SshConstants; import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.OpenSshCertificate; import org.apache.sshd.common.config.keys.PublicKeyEntry; import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; +import org.apache.sshd.common.config.keys.UnsupportedSshPublicKey; import org.apache.sshd.common.digest.BuiltinDigests; import org.apache.sshd.common.mac.Mac; import org.apache.sshd.common.util.io.ModifiableFileWatcher; @@ -126,6 +131,9 @@ public class OpenSshServerKeyDatabase /** Can be used to mark revoked known host lines. */ private static final String MARKER_REVOKED = "revoked"; //$NON-NLS-1$ + /** Marks CA keys used for SSH certificates. */ + private static final String MARKER_CA = "cert-authority"; //$NON-NLS-1$ + private final boolean askAboutNewFile; private final Map<Path, HostKeyFile> knownHostsFiles = new ConcurrentHashMap<>(); @@ -178,7 +186,10 @@ public List<PublicKey> lookup(@NonNull String connectAddress, for (HostKeyFile file : filesToUse) { for (HostEntryPair current : file.get()) { KnownHostEntry entry = current.getHostEntry(); - if (!isRevoked(entry)) { + if (current.getServerKey() instanceof UnsupportedSshPublicKey) { + continue; + } + if (!isRevoked(entry) && !isCertificateAuthority(entry)) { for (SshdSocketAddress host : candidates) { if (entry.isHostMatch(host.getHostName(), host.getPort())) { @@ -204,6 +215,7 @@ public boolean accept(@NonNull String connectAddress, Collection<SshdSocketAddress> candidates = getCandidates(connectAddress, remoteAddress); for (HostKeyFile file : filesToUse) { + HostEntryPair lastModified = modified[0]; try { if (find(candidates, serverKey, file.get(), modified)) { return true; @@ -212,24 +224,35 @@ public boolean accept(@NonNull String connectAddress, ask.revokedKey(remoteAddress, serverKey, file.getPath()); return false; } - if (path == null && modified[0] != null) { + if (modified[0] != lastModified) { // Remember the file in which we might need to update the // entry path = file.getPath(); } } + if (serverKey instanceof OpenSshCertificate) { + return false; + } if (modified[0] != null) { - // We found an entry, but with a different key + // We found an entry, but with a different key. AskUser.ModifiedKeyHandling toDo = ask.acceptModifiedServerKey( remoteAddress, modified[0].getServerKey(), serverKey, path); if (toDo == AskUser.ModifiedKeyHandling.ALLOW_AND_STORE) { - try { - updateModifiedServerKey(serverKey, modified[0], path); - knownHostsFiles.get(path).resetReloadAttributes(); - } catch (IOException e) { - LOG.warn(format(SshdText.get().knownHostsCouldNotUpdate, - path)); + if (modified[0] + .getServerKey() instanceof UnsupportedSshPublicKey) { + // Never update a line containing an unknown key type, + // always add. + addKeyToFile(filesToUse.get(0), candidates, serverKey, ask, + config); + } else { + try { + updateModifiedServerKey(serverKey, modified[0], path); + knownHostsFiles.get(path).resetReloadAttributes(); + } catch (IOException e) { + LOG.warn(format(SshdText.get().knownHostsCouldNotUpdate, + path)); + } } } if (toDo == AskUser.ModifiedKeyHandling.DENY) { @@ -242,19 +265,8 @@ public boolean accept(@NonNull String connectAddress, return true; } else if (ask.acceptUnknownKey(remoteAddress, serverKey)) { if (!filesToUse.isEmpty()) { - HostKeyFile toUpdate = filesToUse.get(0); - path = toUpdate.getPath(); - try { - if (Files.exists(path) || !askAboutNewFile - || ask.createNewFile(path)) { - updateKnownHostsFile(candidates, serverKey, path, - config); - toUpdate.resetReloadAttributes(); - } - } catch (Exception e) { - LOG.warn(format(SshdText.get().knownHostsCouldNotUpdate, - path), e); - } + addKeyToFile(filesToUse.get(0), candidates, serverKey, ask, + config); } return true; } @@ -265,39 +277,90 @@ private static class RevokedKeyException extends Exception { private static final long serialVersionUID = 1L; } - private boolean isRevoked(KnownHostEntry entry) { + private static boolean isRevoked(KnownHostEntry entry) { return MARKER_REVOKED.equals(entry.getMarker()); } + private static boolean isCertificateAuthority(KnownHostEntry entry) { + return MARKER_CA.equals(entry.getMarker()); + } + private boolean find(Collection<SshdSocketAddress> candidates, PublicKey serverKey, List<HostEntryPair> entries, HostEntryPair[] modified) throws RevokedKeyException { + PublicKey keyToCheck = serverKey; + boolean isCert = false; + String keyType = KeyUtils.getKeyType(keyToCheck); + String modifiedKeyType = null; + if (modified[0] != null) { + modifiedKeyType = modified[0].getHostEntry().getKeyEntry() + .getKeyType(); + } + if (serverKey instanceof OpenSshCertificate) { + keyToCheck = ((OpenSshCertificate) serverKey).getCaPubKey(); + isCert = true; + } for (HostEntryPair current : entries) { KnownHostEntry entry = current.getHostEntry(); - for (SshdSocketAddress host : candidates) { - if (entry.isHostMatch(host.getHostName(), host.getPort())) { - boolean revoked = isRevoked(entry); - if (KeyUtils.compareKeys(serverKey, - current.getServerKey())) { - // Exact match - if (revoked) { - throw new RevokedKeyException(); - } + if (candidates.stream().anyMatch(host -> entry + .isHostMatch(host.getHostName(), host.getPort()))) { + boolean revoked = isRevoked(entry); + boolean haveCert = isCertificateAuthority(entry); + if (KeyUtils.compareKeys(keyToCheck, current.getServerKey())) { + // Exact match + if (revoked) { + throw new RevokedKeyException(); + } + if (haveCert == isCert) { modified[0] = null; return true; - } else if (!revoked) { - // Server sent a different key - modified[0] = current; - // Keep going -- maybe there's another entry for this - // host } - break; + } + if (haveCert == isCert && !haveCert && !revoked) { + // Server sent a different key. + if (modifiedKeyType == null) { + modified[0] = current; + modifiedKeyType = entry.getKeyEntry().getKeyType(); + } else if (!keyType.equals(modifiedKeyType)) { + String thisKeyType = entry.getKeyEntry().getKeyType(); + if (isBetterMatch(keyType, thisKeyType, + modifiedKeyType)) { + // Since we may replace the modified[0] key, + // prefer to report a key of the same key type + // as having been modified. + modified[0] = current; + modifiedKeyType = keyType; + } + } + // Keep going -- maybe there's another entry for this + // host } } } return false; } + private static boolean isBetterMatch(String keyType, String thisType, + String modifiedType) { + if (keyType.equals(thisType)) { + return true; + } + // EC keys are a bit special because they encode the curve in the key + // type. If we have no exactly matching EC key type in known_hosts, we + // still prefer to update an existing EC key type over some other key + // type. + if (!keyType.startsWith("ecdsa") || !thisType.startsWith("ecdsa")) { //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + if (!modifiedType.startsWith("ecdsa")) { //$NON-NLS-1$ + return true; + } + // All three are EC keys. thisType doesn't match the size of keyType + // (otherwise the two would have compared equal above already), so it is + // not better than modifiedType. + return false; + } + private List<HostKeyFile> addUserHostKeyFiles(List<String> fileNames) { if (fileNames == null || fileNames.isEmpty()) { return Collections.emptyList(); @@ -317,6 +380,21 @@ private List<HostKeyFile> addUserHostKeyFiles(List<String> fileNames) { return userFiles; } + private void addKeyToFile(HostKeyFile file, + Collection<SshdSocketAddress> candidates, PublicKey serverKey, + AskUser ask, Configuration config) { + Path path = file.getPath(); + try { + if (Files.exists(path) || !askAboutNewFile + || ask.createNewFile(path)) { + updateKnownHostsFile(candidates, serverKey, path, config); + file.resetReloadAttributes(); + } + } catch (Exception e) { + LOG.warn(format(SshdText.get().knownHostsCouldNotUpdate, path), e); + } + } + private void updateKnownHostsFile(Collection<SshdSocketAddress> candidates, PublicKey serverKey, Path path, Configuration config) throws Exception { @@ -453,15 +531,22 @@ public void revokedKey(SocketAddress remoteAddress, PublicKey serverKey, return; } InetSocketAddress remote = (InetSocketAddress) remoteAddress; + boolean isCert = serverKey instanceof OpenSshCertificate; + PublicKey keyToReport = isCert + ? ((OpenSshCertificate) serverKey).getCaPubKey() + : serverKey; URIish uri = JGitUserInteraction.toURI(config.getUsername(), remote); String sha256 = KeyUtils.getFingerPrint(BuiltinDigests.sha256, - serverKey); - String md5 = KeyUtils.getFingerPrint(BuiltinDigests.md5, serverKey); - String keyAlgorithm = serverKey.getAlgorithm(); + keyToReport); + String md5 = KeyUtils.getFingerPrint(BuiltinDigests.md5, + keyToReport); + String keyAlgorithm = keyToReport.getAlgorithm(); + String msg = isCert + ? SshdText.get().knownHostsRevokedCertificateMsg + : SshdText.get().knownHostsRevokedKeyMsg; askUser(provider, uri, null, // - format(SshdText.get().knownHostsRevokedKeyMsg, - remote.getHostString(), path), + format(msg, remote.getHostString(), path), format(SshdText.get().knownHostsKeyFingerprints, keyAlgorithm), md5, sha256); @@ -594,7 +679,7 @@ private List<HostEntryPair> reload(Path path) throws IOException { } try { PublicKey serverKey = keyPart.resolvePublicKey(null, - PublicKeyEntryResolver.IGNORING); + PublicKeyEntryResolver.UNSUPPORTED); if (serverKey == null) { LOG.warn(format( SshdText.get().knownHostsUnknownKeyType, @@ -625,7 +710,7 @@ private int parsePort(String s) { private SshdSocketAddress toSshdSocketAddress(@NonNull String address) { String host = null; - int port = 0; + int port = SshConstants.DEFAULT_PORT; if (HostPatternsHolder.NON_STANDARD_PORT_PATTERN_ENCLOSURE_START_DELIM == address .charAt(0)) { int end = address.indexOf( @@ -665,12 +750,23 @@ private Collection<SshdSocketAddress> getCandidates( if (address != null) { candidates.add(address); } - return candidates; + List<SshdSocketAddress> result = new ArrayList<>(); + result.addAll(candidates); + if (!remoteAddress.isUnresolved()) { + SshdSocketAddress ip = new SshdSocketAddress( + remoteAddress.getAddress().getHostAddress(), + remoteAddress.getPort()); + if (candidates.add(ip)) { + result.add(ip); + } + } + return result; } private String createHostKeyLine(Collection<SshdSocketAddress> patterns, PublicKey key, Configuration config) throws Exception { StringBuilder result = new StringBuilder(); + Set<String> knownNames = new HashSet<>(); if (config.getHashKnownHosts()) { // SHA1 is the only algorithm for host name hashing known to OpenSSH // or to Apache MINA sshd. @@ -680,10 +776,10 @@ private String createHostKeyLine(Collection<SshdSocketAddress> patterns, prng = new SecureRandom(); } byte[] salt = new byte[mac.getDefaultBlockSize()]; - for (SshdSocketAddress address : patterns) { - if (result.length() > 0) { - result.append(','); - } + // For hashed hostnames, only one hashed pattern is allowed per + // https://man.openbsd.org/sshd.8#SSH_KNOWN_HOSTS_FILE_FORMAT + if (!patterns.isEmpty()) { + SshdSocketAddress address = patterns.iterator().next(); prng.nextBytes(salt); KnownHostHashValue.append(result, digester, salt, KnownHostHashValue.calculateHashValue( @@ -692,6 +788,10 @@ private String createHostKeyLine(Collection<SshdSocketAddress> patterns, } } else { for (SshdSocketAddress address : patterns) { + String tgt = address.getHostName() + ':' + address.getPort(); + if (!knownNames.add(tgt)) { + continue; + } if (result.length() > 0) { result.append(','); }
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 2cd0669..900c9fb 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, 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2018, 2024 Thomas Wolf <twolf@apache.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 @@ -47,6 +47,8 @@ private static class PerSessionState { private final Supplier<KeyPasswordProvider> factory; + private PerSessionState noSessionState; + /** * Creates a new {@link PasswordProviderWrapper}. * @@ -59,13 +61,18 @@ public PasswordProviderWrapper( } private PerSessionState getState(SessionContext context) { - PerSessionState state = context.getAttribute(STATE); + PerSessionState state = context != null ? context.getAttribute(STATE) + : noSessionState; if (state == null) { state = new PerSessionState(); state.delegate = factory.get(); state.delegate.setAttempts( PASSWORD_PROMPTS.getRequiredDefault().intValue()); - context.setAttribute(STATE, state); + if (context != null) { + context.setAttribute(STATE, state); + } else { + noSessionState = state; + } } return state; }
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 05f04ac..e401378 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2018, 2024 Thomas Wolf <twolf@apache.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 @@ -83,6 +83,7 @@ public static SshdText get() { /***/ public String knownHostsModifiedKeyDenyMsg; /***/ public String knownHostsModifiedKeyStorePrompt; /***/ public String knownHostsModifiedKeyWarning; + /***/ public String knownHostsRevokedCertificateMsg; /***/ public String knownHostsRevokedKeyMsg; /***/ public String knownHostsUnknownKeyMsg; /***/ public String knownHostsUnknownKeyPrompt; @@ -147,6 +148,71 @@ public static SshdText get() { /***/ public String sshCommandTimeout; /***/ public String sshProcessStillRunning; /***/ public String sshProxySessionCloseFailed; + /***/ public String signAllowedSignersCertAuthorityError; + /***/ public String signAllowedSignersEmptyIdentity; + /***/ public String signAllowedSignersEmptyNamespaces; + /***/ public String signAllowedSignersFormatError; + /***/ public String signAllowedSignersInvalidDate; + /***/ public String signAllowedSignersLineFormat; + /***/ public String signAllowedSignersMultiple; + /***/ public String signAllowedSignersNoIdentities; + /***/ public String signAllowedSignersPublicKeyParsing; + /***/ public String signAllowedSignersUnterminatedQuote; + /***/ public String signCertAlgorithmMismatch; + /***/ public String signCertAlgorithmUnknown; + /***/ public String signCertificateExpired; + /***/ public String signCertificateInvalid; + /***/ public String signCertificateNotForName; + /***/ public String signCertificateRevoked; + /***/ public String signCertificateTooEarly; + /***/ public String signCertificateWithoutPrincipals; + /***/ public String signDefaultKeyEmpty; + /***/ public String signDefaultKeyFailed; + /***/ public String signDefaultKeyInterrupted; + /***/ public String signGarbageAtEnd; + /***/ public String signInvalidAlgorithm; + /***/ public String signInvalidKeyDSA; + /***/ public String signInvalidMagic; + /***/ public String signInvalidNamespace; + /***/ public String signInvalidSignature; + /***/ public String signInvalidVersion; + /***/ public String signKeyExpired; + /***/ public String signKeyRevoked; + /***/ public String signKeyTooEarly; + /***/ public String signKrlBlobLeftover; + /***/ public String signKrlBlobLengthInvalid; + /***/ public String signKrlBlobLengthInvalidExpected; + /***/ public String signKrlCaKeyLengthInvalid; + /***/ public String signKrlCertificateLeftover; + /***/ public String signKrlCertificateSubsectionLeftover; + /***/ public String signKrlCertificateSubsectionLength; + /***/ public String signKrlEmptyRange; + /***/ public String signKrlInvalidBitSetLength; + /***/ public String signKrlInvalidKeyIdLength; + /***/ public String signKrlInvalidMagic; + /***/ public String signKrlInvalidReservedLength; + /***/ public String signKrlInvalidVersion; + /***/ public String signKrlNoCertificateSubsection; + /***/ public String signKrlSerialZero; + /***/ public String signKrlShortRange; + /***/ public String signKrlUnknownSection; + /***/ public String signKrlUnknownSubsection; + /***/ public String signLogFailure; + /***/ public String signMismatchedSignatureAlgorithm; + /***/ public String signNoAgent; + /***/ public String signNoPrincipalMatched; + /***/ public String signNoPublicKey; + /***/ public String signNoSigningKey; + /***/ public String signNotUserCertificate; + /***/ public String signPublicKeyError; + /***/ public String signSeeLog; + /***/ public String signSignatureError; + /***/ public String signStderr; + /***/ public String signTooManyPrivateKeys; + /***/ public String signTooManyPublicKeys; + /***/ public String signUnknownHashAlgorithm; + /***/ public String signUnknownSignatureAlgorithm; + /***/ public String signWrongNamespace; /***/ public String unknownProxyProtocol; }
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java index 8866976..3e1fab3 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/auth/BasicAuthentication.java
@@ -17,8 +17,6 @@ import java.net.PasswordAuthentication; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Arrays; import java.util.concurrent.CancellationException; @@ -113,13 +111,12 @@ public void process() throws Exception { */ protected void askCredentials() { clearPassword(); - PasswordAuthentication auth = AccessController.doPrivileged( - (PrivilegedAction<PasswordAuthentication>) () -> Authenticator - .requestPasswordAuthentication(proxy.getHostString(), - proxy.getAddress(), proxy.getPort(), - SshConstants.SSH_SCHEME, - SshdText.get().proxyPasswordPrompt, "Basic", //$NON-NLS-1$ - null, RequestorType.PROXY)); + PasswordAuthentication auth = Authenticator + .requestPasswordAuthentication(proxy.getHostString(), + proxy.getAddress(), proxy.getPort(), + SshConstants.SSH_SCHEME, + SshdText.get().proxyPasswordPrompt, "Basic", //$NON-NLS-1$ + null, RequestorType.PROXY); if (auth == null) { user = ""; //$NON-NLS-1$ throw new CancellationException(
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/CachingSigningKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/CachingSigningKeyDatabase.java new file mode 100644 index 0000000..4d2d8b6 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/CachingSigningKeyDatabase.java
@@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.signing.ssh; + +/** + * A {@link SigningKeyDatabase} that caches data. + * <p> + * A signing key database may be used to check keys frequently; it may thus need + * to cache some data and it may need to cache data per repository. If an + * implementation does cache data, it is responsible itself for refreshing that + * cache at appropriate times. Clients can control the cache size somewhat via + * {@link #setCacheSize(int)}, although the meaning of the cache size (i.e., its + * unit) is left undefined here. + * </p> + * + * @since 7.1 + */ +public interface CachingSigningKeyDatabase extends SigningKeyDatabase { + + /** + * Retrieves the current cache size. + * + * @return the cache size, or -1 if this database has no cache. + */ + int getCacheSize(); + + /** + * Sets the cache size to use. + * + * @param size + * the cache size, ignored if this database does not have a + * cache. + * @throws IllegalArgumentException + * if {@code size < 0} + */ + void setCacheSize(int size); + + /** + * Discards any cached data. A no-op if the database has no cache. + */ + void clearCache(); +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SigningKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SigningKeyDatabase.java new file mode 100644 index 0000000..eec64c3 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SigningKeyDatabase.java
@@ -0,0 +1,94 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.signing.ssh; + +import java.io.IOException; +import java.security.PublicKey; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.internal.signing.ssh.SigningDatabase; +import org.eclipse.jgit.lib.GpgConfig; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; + +/** + * A database storing meta-information about signing keys and certificates. + * + * @since 7.1 + */ +public interface SigningKeyDatabase { + + /** + * Obtains the current global instance. + * + * @return the global {@link SigningKeyDatabase} + */ + static SigningKeyDatabase getInstance() { + return SigningDatabase.getInstance(); + } + + /** + * Sets the global {@link SigningKeyDatabase}. + * + * @param database + * to set; if {@code null} a default database using the OpenSSH + * allowed signers file and the OpenSSH revocation list mechanism + * is used. + * @return the previously set {@link SigningKeyDatabase} + */ + static SigningKeyDatabase setInstance(SigningKeyDatabase database) { + return SigningDatabase.setInstance(database); + } + + /** + * Determines whether the gives key has been revoked. + * + * @param repository + * {@link Repository} the key is being used in + * @param config + * {@link GpgConfig} to use + * @param key + * {@link PublicKey} to check + * @return {@code true} if the key has been revoked, {@code false} otherwise + * @throws IOException + * if an I/O problem occurred + */ + boolean isRevoked(@NonNull Repository repository, @NonNull GpgConfig config, + @NonNull PublicKey key) throws IOException; + + /** + * Checks whether the given key is allowed to be used for signing, and if + * allowed returns the principal. + * + * @param repository + * {@link Repository} the key is being used in + * @param config + * {@link GpgConfig} to use + * @param key + * {@link PublicKey} to check + * @param namespace + * of the signature + * @param ident + * optional {@link PersonIdent} giving a signer's e-mail address + * and a signature time + * @return {@code null} if the database does not contain any information + * about the given key; the principal if it does and all checks + * passed + * @throws IOException + * if an I/O problem occurred + * @throws VerificationException + * if the database contains information about the key and the + * checks determined that the key is not allowed to be used for + * signing + */ + String isAllowed(@NonNull Repository repository, @NonNull GpgConfig config, + @NonNull PublicKey key, @NonNull String namespace, + PersonIdent ident) throws IOException, VerificationException; +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SshSignatureVerifierFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SshSignatureVerifierFactory.java new file mode 100644 index 0000000..c315428 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SshSignatureVerifierFactory.java
@@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.signing.ssh; + +import org.eclipse.jgit.lib.GpgConfig.GpgFormat; +import org.eclipse.jgit.lib.SignatureVerifier; +import org.eclipse.jgit.internal.signing.ssh.SshSignatureVerifier; +import org.eclipse.jgit.lib.SignatureVerifierFactory; + +/** + * Factory creating {@link SshSignatureVerifier}s. + * + * @since 7.1 + */ +public final class SshSignatureVerifierFactory + implements SignatureVerifierFactory { + + @Override + public GpgFormat getType() { + return GpgFormat.SSH; + } + + @Override + public SignatureVerifier create() { + return new SshSignatureVerifier(); + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SshSignerFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SshSignerFactory.java new file mode 100644 index 0000000..5459b53 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/SshSignerFactory.java
@@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.signing.ssh; + +import org.eclipse.jgit.lib.GpgConfig.GpgFormat; +import org.eclipse.jgit.lib.Signer; +import org.eclipse.jgit.internal.signing.ssh.SshSigner; +import org.eclipse.jgit.lib.SignerFactory; + +/** + * Factory creating {@link SshSigner}s. + * + * @since 7.1 + */ +public final class SshSignerFactory implements SignerFactory { + + @Override + public GpgFormat getType() { + return GpgFormat.SSH; + } + + @Override + public Signer create() { + return new SshSigner(); + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/VerificationException.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/VerificationException.java new file mode 100644 index 0000000..cd77111 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/signing/ssh/VerificationException.java
@@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.signing.ssh; + +/** + * An exception giving details about a failed + * {@link SigningKeyDatabase#isAllowed(org.eclipse.jgit.lib.Repository, org.eclipse.jgit.lib.GpgConfig, java.security.PublicKey, String, org.eclipse.jgit.lib.PersonIdent)} + * validation. + * + * @since 7.1 + */ +public class VerificationException extends Exception { + + private static final long serialVersionUID = 313760495170326160L; + + private final boolean expired; + + private final String reason; + + /** + * Creates a new instance. + * + * @param expired + * whether the checked public key or certificate was expired + * @param reason + * describing the check failure + */ + public VerificationException(boolean expired, String reason) { + this.expired = expired; + this.reason = reason; + } + + @Override + public String getMessage() { + return reason; + } + + /** + * Tells whether the check failed because the public key was expired. + * + * @return {@code true} if the check failed because the public key was + * expired, {@code false} otherwise + */ + public boolean isExpired() { + return expired; + } + + /** + * Retrieves the check failure reason. + * + * @return the reason description + */ + public String getReason() { + return reason; + } +}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyPasswordProviderFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyPasswordProviderFactory.java new file mode 100644 index 0000000..0537300 --- /dev/null +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/KeyPasswordProviderFactory.java
@@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.transport.sshd; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.transport.CredentialsProvider; + +/** + * Maintains a static singleton instance of a factory to create a + * {@link KeyPasswordProvider} from a {@link CredentialsProvider}. + * + * @since 7.1 + */ +public final class KeyPasswordProviderFactory { + + /** + * Creates a {@link KeyPasswordProvider} from a {@link CredentialsProvider}. + */ + @FunctionalInterface + public interface KeyPasswordProviderCreator + extends Function<CredentialsProvider, KeyPasswordProvider> { + // Nothing + } + + private static final KeyPasswordProviderCreator DEFAULT = IdentityPasswordProvider::new; + + private static AtomicReference<KeyPasswordProviderCreator> INSTANCE = new AtomicReference<>( + DEFAULT); + + private KeyPasswordProviderFactory() { + // No instantiation + } + + /** + * Retrieves the currently set {@link KeyPasswordProviderCreator}. + * + * @return the {@link KeyPasswordProviderCreator} + */ + @NonNull + public static KeyPasswordProviderCreator getInstance() { + return INSTANCE.get(); + } + + /** + * Sets a new {@link KeyPasswordProviderCreator}. + * + * @param provider + * to set; if {@code null}, sets a default provider. + * @return the previously set {@link KeyPasswordProviderCreator} + */ + @NonNull + public static KeyPasswordProviderCreator setInstance( + KeyPasswordProviderCreator provider) { + if (provider == null) { + return INSTANCE.getAndSet(DEFAULT); + } + return INSTANCE.getAndSet(provider); + } +}
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 2c3cbe5..4a2eb9c 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, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2018, 2024 Thomas Wolf <twolf@apache.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 @@ -210,7 +210,7 @@ public SshdSession getSession(URIish uri, home, sshDir); KeyIdentityProvider defaultKeysProvider = toKeyIdentityProvider( getDefaultKeys(sshDir)); - Supplier<KeyPasswordProvider> keyPasswordProvider = () -> createKeyPasswordProvider( + Supplier<KeyPasswordProvider> keyPasswordProvider = newKeyPasswordProvider( credentialsProvider); SshClient client = ClientBuilder.builder() .factory(JGitSshClient::new) @@ -574,12 +574,24 @@ protected final KeyCache getKeyCache() { * @param provider * the {@link CredentialsProvider} to delegate to for user * interactions - * @return a new {@link KeyPasswordProvider} + * @return a new {@link KeyPasswordProvider}, or {@code null} to use the + * global {@link KeyPasswordProviderFactory} */ - @NonNull protected KeyPasswordProvider createKeyPasswordProvider( CredentialsProvider provider) { - return new IdentityPasswordProvider(provider); + return null; + } + + private Supplier<KeyPasswordProvider> newKeyPasswordProvider( + CredentialsProvider credentials) { + return () -> { + KeyPasswordProvider provider = createKeyPasswordProvider( + credentials); + if (provider != null) { + return provider; + } + return KeyPasswordProviderFactory.getInstance().apply(credentials); + }; } /**
diff --git a/org.eclipse.jgit.ssh.apache/src/sun/security/x509/README.md b/org.eclipse.jgit.ssh.apache/src/sun/security/x509/README.md deleted file mode 100644 index a84ee37..0000000 --- a/org.eclipse.jgit.ssh.apache/src/sun/security/x509/README.md +++ /dev/null
@@ -1,3 +0,0 @@ -This dummy package is used to fix the error -"Missing requirement: net.i2p.crypto.eddsa 0.3.0 requires 'java.package; sun.security.x509 0.0.0'" -raised since eddsa falsely requires this import \ No newline at end of file
diff --git a/org.eclipse.jgit.ssh.jsch.test/BUILD b/org.eclipse.jgit.ssh.jsch.test/BUILD index 4a8b925..d4e6875 100644 --- a/org.eclipse.jgit.ssh.jsch.test/BUILD +++ b/org.eclipse.jgit.ssh.jsch.test/BUILD
@@ -8,7 +8,9 @@ srcs = glob(["tst/**/*.java"]), tags = ["jsch"], deps = [ - "//lib:eddsa", + "//lib:bcpkix", + "//lib:bcprov", + "//lib:bcutil", "//lib:jsch", "//lib:junit", "//org.eclipse.jgit:jgit",
diff --git a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF index 3bf4edd..34f8e0a 100644 --- a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
@@ -3,19 +3,20 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.jsch.test Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" Import-Package: com.jcraft.jsch;version="[0.1.54,0.2.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit.ssh;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.ssh.jsch;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit.ssh;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.ssh.jsch;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.ssh.jsch.test/pom.xml b/org.eclipse.jgit.ssh.jsch.test/pom.xml index 761b6c4..5f094a7 100644 --- a/org.eclipse.jgit.ssh.jsch.test/pom.xml +++ b/org.eclipse.jgit.ssh.jsch.test/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.jsch.test</artifactId>
diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java index 611d4e8..8aa33e3 100644 --- a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java +++ b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java
@@ -22,7 +22,6 @@ import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.junit.ssh.SshBasicTestBase; import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.RemoteSession; @@ -89,7 +88,8 @@ private OpenSshConfig createConfig(String... content) throws IOException { @Override public void setUp() throws Exception { super.setUp(); - StoredConfig config = ((Repository) db).getConfig(); + @SuppressWarnings("restriction") + StoredConfig config = db.getConfig(); config.setInt("protocol", null, "version", 2); config.save(); }
diff --git a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF index 9da7452..6b0130c 100644 --- a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF
@@ -3,19 +3,19 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.jsch Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch;singleton:=true -Fragment-Host: org.eclipse.jgit;bundle-version="[7.0.0,7.1.0)" +Fragment-Host: org.eclipse.jgit;bundle-version="[7.3.0,7.4.0)" Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/jsch Bundle-ActivationPolicy: lazy -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="7.0.0" +Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="7.3.0" Import-Package: com.jcraft.jsch;version="[0.1.37,0.2.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.io;version="[7.0.0,7.1.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.io;version="[7.3.0,7.4.0)", org.slf4j;version="[1.7.0,3.0.0)"
diff --git a/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF index 1dc0e01..06d0ce3 100644 --- a/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.ssh.jsch - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ssh.jsch/pom.xml b/org.eclipse.jgit.ssh.jsch/pom.xml index a3db63c..03ae29d 100644 --- a/org.eclipse.jgit.ssh.jsch/pom.xml +++ b/org.eclipse.jgit.ssh.jsch/pom.xml
@@ -17,7 +17,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.jsch</artifactId>
diff --git a/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/ssh/jsch/JschSession.java b/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/ssh/jsch/JschSession.java index 5f36dad..ad58ae1 100644 --- a/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/ssh/jsch/JschSession.java +++ b/org.eclipse.jgit.ssh.jsch/src/org/eclipse/jgit/transport/ssh/jsch/JschSession.java
@@ -34,7 +34,6 @@ import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.util.io.IsolatedOutputStream; -import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSchException; @@ -86,22 +85,6 @@ public void disconnect() { } /** - * A kludge to allow {@link org.eclipse.jgit.transport.TransportSftp} to get - * an Sftp channel from Jsch. Ideally, this method would be generic, which - * would require implementing generic Sftp channel operations in the - * RemoteSession class. - * - * @return a channel suitable for Sftp operations. - * @throws com.jcraft.jsch.JSchException - * on problems getting the channel. - * @deprecated since 5.2; use {@link #getFtpChannel()} instead - */ - @Deprecated - public Channel getSftpChannel() throws JSchException { - return sock.openChannel("sftp"); //$NON-NLS-1$ - } - - /** * {@inheritDoc} * * @since 5.2
diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD index 29f5b36..7755df0 100644 --- a/org.eclipse.jgit.test/BUILD +++ b/org.eclipse.jgit.test/BUILD
@@ -53,6 +53,11 @@ exclude = HELPERS + DATA + EXCLUDED, )) + +tests(tests = glob(["exttst/**/*.java"]), + srcprefix = "exttst/", + extra_tags = ["ext"]) + # Non abstract base classes used for tests by other test classes BASE = [ PKG + "internal/storage/file/FileRepositoryBuilderTest.java",
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index ab70d68..7ac93c2 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.test Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -20,65 +20,68 @@ org.apache.commons.compress.compressors.xz;version="[1.15.0,2.0)", org.apache.commons.io;version="[2.15.0,3.0.0)", org.apache.commons.io.output;version="[2.15.0,3.0.0)", + org.apache.commons.lang3;version="[3.17.0,4.0.0)", org.assertj.core.api;version="[3.14.0,4.0.0)", - org.eclipse.jgit.annotations;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api;version="[7.0.0,7.1.0)", - org.eclipse.jgit.api.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.archive;version="[7.0.0,7.1.0)", - org.eclipse.jgit.attributes;version="[7.0.0,7.1.0)", - org.eclipse.jgit.awtui;version="[7.0.0,7.1.0)", - org.eclipse.jgit.blame;version="[7.0.0,7.1.0)", - org.eclipse.jgit.diff;version="[7.0.0,7.1.0)", - org.eclipse.jgit.dircache;version="[7.0.0,7.1.0)", - org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.events;version="[7.0.0,7.1.0)", - org.eclipse.jgit.fnmatch;version="[7.0.0,7.1.0)", - org.eclipse.jgit.gitrepo;version="[7.0.0,7.1.0)", - org.eclipse.jgit.hooks;version="[7.0.0,7.1.0)", - org.eclipse.jgit.ignore;version="[7.0.0,7.1.0)", - org.eclipse.jgit.ignore.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.diff;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.fsck;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.commitgraph;version="7.0.0", - org.eclipse.jgit.internal.storage.dfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.io;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.memory;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.connectivity;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.parser;version="[7.0.0,7.1.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit;version="[7.0.0,7.1.0)", - org.eclipse.jgit.junit.time;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lfs;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.logging;version="[7.0.0,7.1.0)", - org.eclipse.jgit.merge;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.notes;version="[7.0.0,7.1.0)", - org.eclipse.jgit.patch;version="[7.0.0,7.1.0)", - org.eclipse.jgit.pgm;version="[7.0.0,7.1.0)", - org.eclipse.jgit.pgm.internal;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revplot;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.file;version="[7.0.0,7.1.0)", - org.eclipse.jgit.storage.pack;version="[7.0.0,7.1.0)", - org.eclipse.jgit.submodule;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.http;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport.resolver;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.treewalk.filter;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.io;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util.sha1;version="[7.0.0,7.1.0)", + org.eclipse.jgit.annotations;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api;version="[7.3.0,7.4.0)", + org.eclipse.jgit.api.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.archive;version="[7.3.0,7.4.0)", + org.eclipse.jgit.attributes;version="[7.3.0,7.4.0)", + org.eclipse.jgit.awtui;version="[7.3.0,7.4.0)", + org.eclipse.jgit.blame;version="[7.3.0,7.4.0)", + org.eclipse.jgit.blame.cache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.diff;version="[7.3.0,7.4.0)", + org.eclipse.jgit.dircache;version="[7.3.0,7.4.0)", + org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.events;version="[7.3.0,7.4.0)", + org.eclipse.jgit.fnmatch;version="[7.3.0,7.4.0)", + org.eclipse.jgit.gitrepo;version="[7.3.0,7.4.0)", + org.eclipse.jgit.hooks;version="[7.3.0,7.4.0)", + org.eclipse.jgit.ignore;version="[7.3.0,7.4.0)", + org.eclipse.jgit.ignore.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.diff;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.fsck;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.commitgraph;version="7.3.0", + org.eclipse.jgit.internal.storage.dfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.io;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.memory;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.midx;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.connectivity;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.parser;version="[7.3.0,7.4.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit;version="[7.3.0,7.4.0)", + org.eclipse.jgit.junit.time;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lfs;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.logging;version="[7.3.0,7.4.0)", + org.eclipse.jgit.merge;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.notes;version="[7.3.0,7.4.0)", + org.eclipse.jgit.patch;version="[7.3.0,7.4.0)", + org.eclipse.jgit.pgm;version="[7.3.0,7.4.0)", + org.eclipse.jgit.pgm.internal;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revplot;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.file;version="[7.3.0,7.4.0)", + org.eclipse.jgit.storage.pack;version="[7.3.0,7.4.0)", + org.eclipse.jgit.submodule;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.http;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport.resolver;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.treewalk.filter;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.io;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util.sha1;version="[7.3.0,7.4.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", org.junit.function;version="[4.13.0,5.0.0)",
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/midx/CgitMidxCompatibilityTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/midx/CgitMidxCompatibilityTest.java new file mode 100644 index 0000000..88f0806 --- /dev/null +++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/midx/CgitMidxCompatibilityTest.java
@@ -0,0 +1,208 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OBJECTOFFSETS; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDFANOUT; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDLOOKUP; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_PACKNAMES; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.file.Pack; +import org.eclipse.jgit.internal.storage.file.PackFile; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; +import org.eclipse.jgit.util.NB; +import org.junit.Test; + +public class CgitMidxCompatibilityTest extends SampleDataRepositoryTestCase { + + @Test + public void jgitMidx_verifyByCgit() + throws IOException, InterruptedException { + byte[] jgitMidxBytes = generateJGitMidx(); + writeMidx(jgitMidxBytes); + assertEquals("cgit exit code", 0, run_cgit_multipackindex_verify()); + } + + @Test + public void compareBasicChunkSizes() + throws IOException, InterruptedException { + // We cannot compare byte-by-byte because there are optional chunks and + // it is not guaranteed what cgit and jgit will generate + byte[] jgitMidxBytes = generateJGitMidx(); + assertEquals("cgit exit code", 0, run_cgit_multipackindex_write()); + byte[] cgitMidxBytes = readCgitMidx(); + + RawMultiPackIndex jgitMidx = new RawMultiPackIndex(jgitMidxBytes); + RawMultiPackIndex cgitMidx = new RawMultiPackIndex(cgitMidxBytes); + + // This is a fixed sized chunk + assertEquals(256 * 4, cgitMidx.getChunkSize(MIDX_CHUNKID_OIDFANOUT)); + assertArrayEquals(cgitMidx.getRawChunk(MIDX_CHUNKID_OIDFANOUT), + jgitMidx.getRawChunk(MIDX_CHUNKID_OIDFANOUT)); + + assertArrayEquals(cgitMidx.getRawChunk(MIDX_CHUNKID_OIDLOOKUP), + jgitMidx.getRawChunk(MIDX_CHUNKID_OIDLOOKUP)); + + // The spec has changed from padding packnames to a multile of four, to + // move the packname chunk to the end of the file. + // git 2.48 pads the packs names to a multiple of 4 + // jgit puts the chunk at the end + byte[] cgitPacknames = trimPadding( + cgitMidx.getRawChunk(MIDX_CHUNKID_PACKNAMES)); + assertArrayEquals(cgitPacknames, + jgitMidx.getRawChunk(MIDX_CHUNKID_PACKNAMES)); + + assertArrayEquals(cgitMidx.getRawChunk(MIDX_CHUNKID_OBJECTOFFSETS), + jgitMidx.getRawChunk(MIDX_CHUNKID_OBJECTOFFSETS)); + + } + + private byte[] generateJGitMidx() throws IOException { + Map<String, PackIndex> indexes = new HashMap<>(); + for (Pack pack : db.getObjectDatabase().getPacks()) { + PackFile packFile = pack.getPackFile().create(PackExt.INDEX); + indexes.put(packFile.getName(), pack.getIndex()); + } + + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, indexes); + return out.toByteArray(); + } + + private int run_cgit_multipackindex_write() + throws IOException, InterruptedException { + String[] command = new String[] { "git", "multi-pack-index", "write" }; + Process proc = Runtime.getRuntime().exec(command, new String[0], + db.getDirectory()); + return proc.waitFor(); + } + + private int run_cgit_multipackindex_verify() + throws IOException, InterruptedException { + String[] command = new String[] { "git", "multi-pack-index", "verify" }; + Process proc = Runtime.getRuntime().exec(command, new String[0], + db.getDirectory()); + return proc.waitFor(); + } + + private byte[] readCgitMidx() throws IOException { + File midx = getMIdxStandardLocation(); + assertTrue("cgit multi-pack-index exists", midx.exists()); + return Files.readAllBytes(midx.toPath()); + } + + private void writeMidx(byte[] midx) throws IOException { + File midxFile = getMIdxStandardLocation(); + Files.write(midxFile.toPath(), midx); + } + + private File getMIdxStandardLocation() { + return new File(db.getObjectDatabase().getPackDirectory(), + "multi-pack-index"); + } + + private byte[] trimPadding(byte[] data) { + // Chunk MUST have one \0, we want to remove any extra \0 + int newEnd = data.length - 1; + while (newEnd - 1 >= 0 && data[newEnd - 1] == 0) { + newEnd--; + } + + if (newEnd == data.length - 1) { + return data; + } + return Arrays.copyOfRange(data, 0, newEnd + 1); + } + + private static class RawMultiPackIndex { + private final List<ChunkSegment> chunks; + + private final byte[] midx; + + private RawMultiPackIndex(byte[] midx) { + this.chunks = readChunks(midx); + this.midx = midx; + } + + long getChunkSize(int chunkId) { + int chunkPos = findChunkPosition(chunks, chunkId); + return chunks.get(chunkPos + 1).offset + - chunks.get(chunkPos).offset; + } + + long getOffset(int chunkId) { + return chunks.get(findChunkPosition(chunks, chunkId)).offset; + } + + private long getNextOffset(int chunkId) { + return chunks.get(findChunkPosition(chunks, chunkId) + 1).offset; + } + + byte[] getRawChunk(int chunkId) { + int start = (int) getOffset(chunkId); + int end = (int) getNextOffset(chunkId); + return Arrays.copyOfRange(midx, start, end); + } + + private static int findChunkPosition(List<ChunkSegment> chunks, + int id) { + int chunkPos = -1; + for (int i = 0; i < chunks.size(); i++) { + if (chunks.get(i).id() == id) { + chunkPos = i; + break; + } + } + if (chunkPos == -1) { + throw new IllegalStateException("Chunk doesn't exist"); + } + return chunkPos; + } + + private List<ChunkSegment> readChunks(byte[] midx) { + // Read the number of "chunkOffsets" (1 byte) + int chunkCount = midx[6]; + byte[] lookupBuffer = new byte[CHUNK_LOOKUP_WIDTH + * (chunkCount + 1)]; + System.arraycopy(midx, 12, lookupBuffer, 0, lookupBuffer.length); + + List<ChunkSegment> chunks = new ArrayList<>(chunkCount + 1); + for (int i = 0; i <= chunkCount; i++) { + // chunks[chunkCount] is just a marker, in order to record the + // length of the last chunk. + int id = NB.decodeInt32(lookupBuffer, i * 12); + long offset = NB.decodeInt64(lookupBuffer, i * 12 + 4); + chunks.add(new ChunkSegment(id, offset)); + } + return chunks; + } + } + + private record ChunkSegment(int id, long offset) { + } +}
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index 05f7c08..9cf21fd 100644 --- a/org.eclipse.jgit.test/pom.xml +++ b/org.eclipse.jgit.test/pom.xml
@@ -19,7 +19,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl index 170bf0c..41f76d0 100644 --- a/org.eclipse.jgit.test/tests.bzl +++ b/org.eclipse.jgit.test/tests.bzl
@@ -1,11 +1,29 @@ +''' +Expose each test as a bazel target +''' load( "@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests", ) -def tests(tests): +def tests(tests, srcprefix="tst/", extra_tags=[]): + ''' + Create a target each of the tests + + Each target is the full push (removing srcprefix) replacing directory + separators with underscores. + + e.g. a test under tst/a/b/c/A.test will become the target + //org.eclipse.jgit.tests:a_b_c_A + + Args: + tests: a glob of tests files + srcprefix: prefix between org.eclipse.jgit.tests and the package + start + extra_tags: additional tags to add to the generated targets + ''' for src in tests: - name = src[len("tst/"):len(src) - len(".java")].replace("/", "_") + name = src[len(srcprefix):len(src) - len(".java")].replace("/", "_") labels = [] timeout = "moderate" if name.startswith("org_eclipse_jgit_"): @@ -20,6 +38,8 @@ if "lib" not in labels: labels.append("lib") + labels.extend(extra_tags) + # TODO(http://eclip.se/534285): Make this test pass reliably # and remove the flaky attribute. flaky = src.endswith("CrissCrossMergeTest.java")
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds.patch new file mode 100644 index 0000000..6e7448b --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds.patch
@@ -0,0 +1,10 @@ +diff --git a/ConflictOutOfBounds b/ConflictOutOfBounds +index 0000000..de98044 +--- a/ConflictOutOfBounds ++++ b/ConflictOutOfBounds +@@ -25,4 +25,4 @@ + line3 +-lineA ++lineB + line5 + line6
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds_PostImage new file mode 100644 index 0000000..4e5d5b2 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds_PostImage
@@ -0,0 +1,15 @@ +line1 +line2 +line3 +line4 +line5 +line6 +line7 +line8 +<<<<<<< HEAD +======= +line3 +lineB +line5 +line6 +>>>>>>> PATCH
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds_PreImage new file mode 100644 index 0000000..f62562a --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/ConflictOutOfBounds_PreImage
@@ -0,0 +1,8 @@ +line1 +line2 +line3 +line4 +line5 +line6 +line7 +line8
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict.patch new file mode 100644 index 0000000..a99e636 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict.patch
@@ -0,0 +1,10 @@ +diff --git a/allowconflict b/allowconflict +index 0000000..de98044 +--- a/allowconflict ++++ b/allowconflict +@@ -3,4 +3,4 @@ + line3 +-lineA ++lineB + line5 + line6
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_PostImage new file mode 100644 index 0000000..a963b40 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_PostImage
@@ -0,0 +1,15 @@ +line1 +line2 +<<<<<<< HEAD +line3 +line4 +line5 +line6 +======= +line3 +lineB +line5 +line6 +>>>>>>> PATCH +line7 +line8
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_PreImage new file mode 100644 index 0000000..f62562a --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_PreImage
@@ -0,0 +1,8 @@ +line1 +line2 +line3 +line4 +line5 +line6 +line7 +line8
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_file_deleted.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_file_deleted.patch new file mode 100644 index 0000000..c9655a5 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/allowconflict_file_deleted.patch
@@ -0,0 +1,10 @@ +diff --git a/allowconflict_file_deleted b/allowconflict_file_deleted +index 0000000..de98044 +--- a/allowconflict_file_deleted ++++ b/allowconflict_file_deleted +@@ -3,4 +3,4 @@ + line3 +-lineA ++lineB + line5 + line6
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c new file mode 100644 index 0000000..3661160 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c
@@ -0,0 +1,43 @@ +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +void getGreeting(char *result, const char *name) { + sprintf(result, "Hello, %s!", name); +} + +void getFarewell(char *result, const char *name) { + sprintf(result, "Goodbye, %s. Have a great day!", name); +} + +void toLower(char *str) { + for (int i = 0; str[i]; i++) { + str[i] = tolower(str[i]); + } +} + +void getPersonalizedGreeting(char *result, const char *name, const char *timeOfDay) { + char timeOfDayLower[50]; + strcpy(timeOfDayLower, timeOfDay); + toLower(timeOfDayLower); + if (strcmp(timeOfDayLower, "morning") == 0) { + sprintf(result, "Good morning, %s", name); + } else if (strcmp(timeOfDayLower, "afternoon") == 0) { + sprintf(result, "Good afternoon, %s", name); + } else if (strcmp(timeOfDayLower, "evening") == 0) { + sprintf(result, "Good evening, %s", name); + } else { + sprintf(result, "Good day, %s", name); + } +} + +int main() { + char result[100]; + getGreeting(result, "foo"); + printf("%s\\n", result); + getFarewell(result, "bar"); + printf("%s\\n", result); + getPersonalizedGreeting(result, "baz", "morning"); + printf("%s\\n", result); + return 0; +}
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource new file mode 100644 index 0000000..9659685 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource
@@ -0,0 +1,37 @@ +public class Greeting { + public String getGreeting(String name) { + String msg = "Hello, " + name + "!"; + return msg; + } + + public String getFarewell(String name) { + String msg = "Goodbye, " + name + ". Have a great day!"; + return msg; + } + + public String getPersonalizedGreeting(String name, String timeOfDay) { + String msg; + switch (timeOfDay.toLowerCase()) { + case "morning": + msg = "Good morning, " + name; + break; + case "afternoon": + msg = "Good afternoon, " + name; + break; + case "evening": + msg = "Good evening, " + name; + break; + default: + msg = "Good day, " + name; + break; + } + return msg; + } + + public static void main(String[] args) { + Greeting greeting = new Greeting(); + System.out.println(greeting.getGreeting("foo")); + System.out.println(greeting.getFarewell("bar")); + System.out.println(greeting.getPersonalizedGreeting("baz", "morning")); + } +}
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py new file mode 100644 index 0000000..9eda6cd --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py
@@ -0,0 +1,26 @@ +class Greeting: + def get_greeting(self, name): + greeting_message = f"Hello, {name}!" + return greeting_message + + def get_farewell(self, name): + farewell_message = f"Goodbye, {name}. Have a great day!" + return farewell_message + + def get_personalized_greeting(self, name, time_of_day): + time_of_day = time_of_day.lower() + if time_of_day == "morning": + personalized_message = f"Good morning, {name}" + elif time_of_day == "afternoon": + personalized_message = f"Good afternoon, {name}" + elif time_of_day == "evening": + personalized_message = f"Good evening, {name}" + else: + personalized_message = f"Good day, {name}" + return personalized_message + +if __name__ == "__main__": + greeting = Greeting() + print(greeting.get_greeting("foo")) + print(greeting.get_farewell("bar")) + print(greeting.get_personalized_greeting("baz", "morning"))
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs new file mode 100644 index 0000000..a3aa5cb --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs
@@ -0,0 +1,27 @@ +struct Greeting; + +impl Greeting { + fn get_greeting(&self, name: &str) -> String { + format!("Hello, {}!", name) + } + + fn get_farewell(&self, name: &str) -> String { + format!("Goodbye, {}. Have a great day!", name) + } + + fn get_personalized_greeting(&self, name: &str, time_of_day: &str) -> String { + match time_of_day.to_lowercase().as_str() { + "morning" => format!("Good morning, {}", name), + "afternoon" => format!("Good afternoon, {}", name), + "evening" => format!("Good evening, {}", name), + _ => format!("Good day, {}", name), + } + } +} + +fn main() { + let greeting = Greeting; + println!("{}", greeting.get_greeting("foo")); + println!("{}", greeting.get_farewell("bar")); + println!("{}", greeting.get_personalized_greeting("baz", "morning")); +}
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi new file mode 100644 index 0000000..6aa4ecd --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi
@@ -0,0 +1,25 @@ +/dts-v1/; + +/ { + model = "Example Board"; + compatible = "example,board"; + cpus { + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x20000000>; + }; + + uart0: uart@101f1000 { + compatible = "ns16550a"; + reg = <0x101f1000 0x1000>; + interrupts = <5>; + clock-frequency = <24000000>; + }; +};
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java index 1c2e995..2266772 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -1,6 +1,6 @@ /* * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> - * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> and others + * Copyright (C) 2010, 2025 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 @@ -665,11 +665,13 @@ public void testAddRemovedFile() throws Exception { FileUtils.delete(file); // is supposed to do nothing - dc = git.add().addFilepattern("a.txt").call(); + dc = git.add().addFilepattern("a.txt").setAll(false).call(); assertEquals(oid, dc.getEntry(0).getObjectId()); assertEquals( "[a.txt, mode:100644, content:content]", indexState(CONTENT)); + git.add().addFilepattern("a.txt").call(); + assertEquals("", indexState(CONTENT)); } } @@ -690,11 +692,13 @@ public void testAddRemovedCommittedFile() throws Exception { FileUtils.delete(file); // is supposed to do nothing - dc = git.add().addFilepattern("a.txt").call(); + dc = git.add().addFilepattern("a.txt").setAll(false).call(); assertEquals(oid, dc.getEntry(0).getObjectId()); assertEquals( "[a.txt, mode:100644, content:content]", indexState(CONTENT)); + git.add().addFilepattern("a.txt").call(); + assertEquals("", indexState(CONTENT)); } } @@ -964,7 +968,7 @@ public void testAddWithoutParameterUpdate() throws Exception { // file sub/b.txt is deleted FileUtils.delete(file2); - git.add().addFilepattern("sub").call(); + git.add().addFilepattern("sub").setAll(false).call(); // change in sub/a.txt is staged // deletion of sub/b.txt is not staged // sub/c.txt is staged @@ -973,6 +977,12 @@ public void testAddWithoutParameterUpdate() throws Exception { "[sub/b.txt, mode:100644, content:content b]" + "[sub/c.txt, mode:100644, content:content c]", indexState(CONTENT)); + git.add().addFilepattern("sub").call(); + // deletion of sub/b.txt is staged + assertEquals( + "[sub/a.txt, mode:100644, content:modified content]" + + "[sub/c.txt, mode:100644, content:content c]", + indexState(CONTENT)); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java index 3a4ea8e..9c2b16a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
@@ -267,7 +267,10 @@ private void archiveHeadAllFilesWithCompression(String fmt) throws Exception { archive(git, archive, fmt, Map.of("compression-level", 9)); int sizeCompression9 = getNumBytes(archive); - assertTrue(sizeCompression1 > sizeCompression9); + assertTrue( + "Expected sizeCompression1 = " + sizeCompression1 + + " > sizeCompression9 = " + sizeCompression9, + sizeCompression1 > sizeCompression9); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java index be3b33a..3f5c5da 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
@@ -34,6 +34,7 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.merge.ContentMergeStrategy; @@ -529,10 +530,11 @@ private void doCherryPickAndCheckResult(final Git git, assertEquals(RepositoryState.SAFE, db.getRepositoryState()); if (reason == null) { - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue(reader.getLastEntry().getComment() .startsWith("cherry-pick: ")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue(reader.getLastEntry().getComment() .startsWith("cherry-pick: ")); }
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 63ab809..661878f 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
@@ -182,7 +182,8 @@ private static boolean isLocalHead(Ref ref) { private static boolean hasRefLog(Repository repo, Ref ref) { try { - return repo.getReflogReader(ref.getName()).getLastEntry() != null; + return repo.getRefDatabase().getReflogReader(ref) + .getLastEntry() != null; } catch (IOException ioe) { throw new IllegalStateException(ioe); } @@ -647,7 +648,8 @@ public void testCloneRepositoryWithSubmodules() throws Exception { new File(git.getRepository().getWorkTree(), walk.getPath()), subRepo.getWorkTree()); assertEquals(new File(new File(git.getRepository().getDirectory(), - "modules"), walk.getPath()), subRepo.getDirectory()); + "modules"), walk.getPath()).getCanonicalPath(), + subRepo.getDirectory().getCanonicalPath()); } File directory = createTempDirectory("testCloneRepositoryWithSubmodules"); @@ -681,8 +683,8 @@ public void testCloneRepositoryWithSubmodules() throws Exception { walk.getPath()), clonedSub1.getWorkTree()); assertEquals( new File(new File(git2.getRepository().getDirectory(), - "modules"), walk.getPath()), - clonedSub1.getDirectory()); + "modules"), walk.getPath()).getCanonicalPath(), + clonedSub1.getDirectory().getCanonicalPath()); } } @@ -770,8 +772,8 @@ public void testCloneRepositoryWithNestedSubmodules() throws Exception { walk.getPath()), clonedSub1.getWorkTree()); assertEquals( new File(new File(git2.getRepository().getDirectory(), - "modules"), walk.getPath()), - clonedSub1.getDirectory()); + "modules"), walk.getPath()).getCanonicalPath(), + clonedSub1.getDirectory().getCanonicalPath()); status = new SubmoduleStatusCommand(clonedSub1); statuses = status.call(); } @@ -795,7 +797,7 @@ public void testCloneWithAutoSetupRebase() throws Exception { assertNull(git2.getRepository().getConfig().getEnum( BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, "test", - ConfigConstants.CONFIG_KEY_REBASE, null)); + ConfigConstants.CONFIG_KEY_REBASE)); StoredConfig userConfig = SystemReader.getInstance() .getUserConfig(); @@ -811,7 +813,6 @@ public void testCloneWithAutoSetupRebase() throws Exception { addRepoToClose(git2.getRepository()); assertEquals(BranchRebaseMode.REBASE, git2.getRepository().getConfig().getEnum( - BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, "test", ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE)); @@ -828,7 +829,6 @@ public void testCloneWithAutoSetupRebase() throws Exception { addRepoToClose(git2.getRepository()); assertEquals(BranchRebaseMode.REBASE, git2.getRepository().getConfig().getEnum( - BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, "test", ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java index 57e5d49..4e5f44e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
@@ -26,6 +26,7 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.revwalk.RevCommit; @@ -69,10 +70,11 @@ public void testSomeCommits() throws Exception { l--; } assertEquals(l, -1); - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue( reader.getLastEntry().getComment().startsWith("commit:")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue( reader.getLastEntry().getComment().startsWith("commit:")); } @@ -248,10 +250,11 @@ public void testCommitAmend() throws Exception { c++; } assertEquals(1, c); - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue(reader.getLastEntry().getComment() .startsWith("commit (amend):")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue(reader.getLastEntry().getComment() .startsWith("commit (amend):")); }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 35de73e..21cfcc4 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -19,14 +19,15 @@ import static org.junit.Assume.assumeTrue; import java.io.File; -import java.util.Date; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.List; -import java.util.TimeZone; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus; import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.api.errors.EmptyCommitException; +import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.dircache.DirCache; @@ -34,19 +35,23 @@ import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.time.TimeUtil; -import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.CommitConfig.CleanupMode; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.GpgSigner; +import org.eclipse.jgit.lib.GpgConfig; +import org.eclipse.jgit.lib.GpgConfig.GpgFormat; +import org.eclipse.jgit.lib.GpgSignature; +import org.eclipse.jgit.lib.ObjectBuilder; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.Signer; +import org.eclipse.jgit.lib.Signers; import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.lib.CommitConfig.CleanupMode; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.submodule.SubmoduleWalk; @@ -430,10 +435,12 @@ public void commitAfterSquashMerge() throws Exception { assertEquals(1, squashedCommit.getParentCount()); assertNull(db.readSquashCommitMsg()); - assertEquals("commit: Squashed commit of the following:", db - .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("commit: Squashed commit of the following:", db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("commit: Squashed commit of the following:", + db.getRefDatabase().getReflogReader(Constants.HEAD) + .getLastEntry().getComment()); + assertEquals("commit: Squashed commit of the following:", + db.getRefDatabase().getReflogReader(db.getFullBranch()) + .getLastEntry().getComment()); } } @@ -450,12 +457,15 @@ public void testReflogs() throws Exception { git.commit().setMessage("c3").setAll(true) .setReflogComment("testRl").call(); - db.getReflogReader(Constants.HEAD).getReverseEntries(); + db.getRefDatabase().getReflogReader(Constants.HEAD) + .getReverseEntries(); assertEquals("testRl;commit (initial): c1;", reflogComments( - db.getReflogReader(Constants.HEAD).getReverseEntries())); + db.getRefDatabase().getReflogReader(Constants.HEAD) + .getReverseEntries())); assertEquals("testRl;commit (initial): c1;", reflogComments( - db.getReflogReader(db.getBranch()).getReverseEntries())); + db.getRefDatabase().getReflogReader(db.getFullBranch()) + .getReverseEntries())); } } @@ -481,11 +491,11 @@ public void commitAmendWithoutAuthorShouldSetOriginalAuthorAndAuthorTime() writeTrashFile("file1", "file1"); git.add().addFilepattern("file1").call(); - final String authorName = "First Author"; - final String authorEmail = "author@example.org"; - final Date authorDate = new Date(1349621117000L); + String authorName = "First Author"; + String authorEmail = "author@example.org"; + Instant authorDate = Instant.ofEpochSecond(1349621117L); PersonIdent firstAuthor = new PersonIdent(authorName, authorEmail, - authorDate, TimeZone.getTimeZone("UTC")); + authorDate, ZoneOffset.UTC); git.commit().setMessage("initial commit").setAuthor(firstAuthor).call(); RevCommit amended = git.commit().setAmend(true) @@ -494,7 +504,8 @@ public void commitAmendWithoutAuthorShouldSetOriginalAuthorAndAuthorTime() PersonIdent amendedAuthor = amended.getAuthorIdent(); assertEquals(authorName, amendedAuthor.getName()); assertEquals(authorEmail, amendedAuthor.getEmailAddress()); - assertEquals(authorDate.getTime(), amendedAuthor.getWhen().getTime()); + assertEquals(authorDate.getEpochSecond(), + amendedAuthor.getWhenAsInstant().getEpochSecond()); } } @@ -839,21 +850,39 @@ public void callSignerWithProperSigningKey() throws Exception { String[] signingKey = new String[1]; PersonIdent[] signingCommitters = new PersonIdent[1]; AtomicInteger callCount = new AtomicInteger(); - GpgSigner.setDefault(new GpgSigner() { + // Since GpgFormat defaults to OpenPGP just set a new signer for + // that. + Signers.set(GpgFormat.OPENPGP, new Signer() { + @Override - public void sign(CommitBuilder commit, String gpgSigningKey, - PersonIdent signingCommitter, CredentialsProvider credentialsProvider) { - signingKey[0] = gpgSigningKey; + public void signObject(Repository repo, GpgConfig config, + ObjectBuilder builder, PersonIdent signingCommitter, + String signingKeySpec, + CredentialsProvider credentialsProvider) + throws CanceledException, + UnsupportedSigningFormatException { + signingKey[0] = signingKeySpec; signingCommitters[0] = signingCommitter; callCount.incrementAndGet(); } @Override - public boolean canLocateSigningKey(String gpgSigningKey, - PersonIdent signingCommitter, + public GpgSignature sign(Repository repo, GpgConfig config, + byte[] data, PersonIdent signingCommitter, + String signingKeySpec, + CredentialsProvider credentialsProvider) + throws CanceledException, + UnsupportedSigningFormatException { + throw new CanceledException("Unexpected call"); + } + + @Override + public boolean canLocateSigningKey(Repository repo, + GpgConfig config, PersonIdent signingCommitter, + String signingKeySpec, CredentialsProvider credentialsProvider) throws CanceledException { - return false; + throw new CanceledException("Unexpected call"); } }); @@ -904,19 +933,37 @@ public void callSignerOnlyWhenSigning() throws Exception { git.add().addFilepattern("file1").call(); AtomicInteger callCount = new AtomicInteger(); - GpgSigner.setDefault(new GpgSigner() { + // Since GpgFormat defaults to OpenPGP just set a new signer for + // that. + Signers.set(GpgFormat.OPENPGP, new Signer() { + @Override - public void sign(CommitBuilder commit, String gpgSigningKey, - PersonIdent signingCommitter, CredentialsProvider credentialsProvider) { + public void signObject(Repository repo, GpgConfig config, + ObjectBuilder builder, PersonIdent signingCommitter, + String signingKeySpec, + CredentialsProvider credentialsProvider) + throws CanceledException, + UnsupportedSigningFormatException { callCount.incrementAndGet(); } @Override - public boolean canLocateSigningKey(String gpgSigningKey, - PersonIdent signingCommitter, + public GpgSignature sign(Repository repo, GpgConfig config, + byte[] data, PersonIdent signingCommitter, + String signingKeySpec, + CredentialsProvider credentialsProvider) + throws CanceledException, + UnsupportedSigningFormatException { + throw new CanceledException("Unexpected call"); + } + + @Override + public boolean canLocateSigningKey(Repository repo, + GpgConfig config, PersonIdent signingCommitter, + String signingKeySpec, CredentialsProvider credentialsProvider) throws CanceledException { - return false; + throw new CanceledException("Unexpected call"); } });
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java index ab87fa9..060e6d3 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
@@ -12,6 +12,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -87,6 +88,9 @@ public void testDescribe() throws Exception { assertEquals("alice-t1", describe(c2, "alice*")); assertEquals("alice-t1", describe(c2, "a*", "b*", "c*")); + assertNotEquals("alice-t1", describeExcluding(c2, "alice*")); + assertNotEquals("alice-t1", describeCommand(c2).setMatch("*").setExclude("alice*").call()); + assertEquals("bob-t2", describe(c3)); assertEquals("bob-t2-0-g44579eb", describe(c3, true, false)); assertEquals("alice-t1-1-g44579eb", describe(c3, "alice*")); @@ -95,6 +99,15 @@ public void testDescribe() throws Exception { assertEquals("bob-t2", describe(c3, "?ob*")); assertEquals("bob-t2", describe(c3, "a*", "b*", "c*")); + assertNotEquals("alice-t1-1-g44579eb", describeExcluding(c3, "alice*")); + assertNotEquals("alice-t1-1-g44579eb", describeCommand(c3).setMatch("*").setExclude("alice*").call()); + assertNotEquals("alice-t1-1-g44579eb", describeExcluding(c3, "a??c?-t*")); + assertNotEquals("alice-t1-1-g44579eb", describeCommand(c3).setMatch("bob*").setExclude("a??c?-t*").call()); + assertNotEquals("bob-t2", describeExcluding(c3, "bob*")); + assertNotEquals("bob-t2", describeCommand(c3).setMatch("alice*").setExclude("bob*")); + assertNotEquals("bob-t2", describeExcluding(c3, "?ob*")); + assertNotEquals("bob-t2", describeCommand(c3).setMatch("a??c?-t*").setExclude("?ob*")); + // the value verified with git-describe(1) assertEquals("bob-t2-1-g3e563c5", describe(c4)); assertEquals("bob-t2-1-g3e563c5", describe(c4, true, false)); @@ -518,6 +531,15 @@ private String describe(ObjectId c1, String... patterns) throws Exception { .setMatch(patterns).call(); } + private String describeExcluding(ObjectId c1, String... patterns) throws Exception { + return git.describe().setTarget(c1).setTags(describeUseAllTags) + .setExclude(patterns).call(); + } + + private DescribeCommand describeCommand(ObjectId c1) throws Exception { + return git.describe().setTarget(c1).setTags(describeUseAllTags); + } + private static void assertNameStartsWith(ObjectId c4, String prefix) { assertTrue(c4.name(), c4.name().startsWith(prefix)); }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java index b937b1f..4c971ff 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
@@ -559,7 +559,7 @@ private void setupGitAndDoHardReset(AutoCRLF autoCRLF, EOL eol, } if (infoAttributesContent != null) { - File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES); + File f = new File(db.getCommonDirectory(), Constants.INFO_ATTRIBUTES); write(f, infoAttributesContent); } config.save();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java index 3ec454c..3731347 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
@@ -92,8 +92,8 @@ public void testFetchHasRefLogForRemoteRef() throws Exception { assertTrue(remoteRef.getName().startsWith(Constants.R_REMOTES)); assertEquals(defaultBranchSha1, remoteRef.getObjectId()); - assertNotNull(git.getRepository().getReflogReader(remoteRef.getName()) - .getLastEntry()); + assertNotNull(git.getRepository().getRefDatabase() + .getReflogReader(remoteRef.getName()).getLastEntry()); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java index f98db34..6090d5e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
@@ -11,12 +11,11 @@ import static org.junit.Assert.assertTrue; -import java.util.Date; +import java.time.Instant; import java.util.Properties; import org.eclipse.jgit.junit.RepositoryTestCase; -import org.eclipse.jgit.util.GitDateParser; -import org.eclipse.jgit.util.SystemReader; +import org.eclipse.jgit.util.GitTimeParser; import org.junit.Before; import org.junit.Test; @@ -36,9 +35,8 @@ public void setUp() throws Exception { @Test public void testGConeCommit() throws Exception { - Date expire = GitDateParser.parse("now", null, SystemReader - .getInstance().getLocale()); - Properties res = git.gc().setExpire(expire).call(); + Instant expireNow = GitTimeParser.parseInstant("now"); + Properties res = git.gc().setExpire(expireNow).call(); assertTrue(res.size() == 8); } @@ -52,11 +50,8 @@ public void testGCmoreCommits() throws Exception { writeTrashFile("b.txt", "a couple of words for gc to pack more 2"); writeTrashFile("c.txt", "a couple of words for gc to pack more 3"); git.commit().setAll(true).setMessage("commit3").call(); - Properties res = git - .gc() - .setExpire( - GitDateParser.parse("now", null, SystemReader - .getInstance().getLocale())).call(); + Instant expireNow = GitTimeParser.parseInstant("now"); + Properties res = git.gc().setExpire(expireNow).call(); assertTrue(res.size() == 8); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java index 7693434..e847e72 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
@@ -14,6 +14,7 @@ import java.io.File; import java.io.IOException; +import java.time.Instant; import org.eclipse.jgit.api.ListBranchCommand.ListMode; import org.eclipse.jgit.api.errors.GitAPIException; @@ -100,7 +101,7 @@ public void testClose() throws IOException, JGitInternalException, GitAPIException { File workTree = db.getWorkTree(); Git git = Git.open(workTree); - git.gc().setExpire(null).call(); + git.gc().setExpire((Instant) null).call(); git.checkout().setName(git.getRepository().resolve("HEAD^").getName()) .call(); try {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java new file mode 100644 index 0000000..3b60e1b --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java
@@ -0,0 +1,192 @@ +/* + * Copyright (C) 2024, Broadcom 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.api; + +import static org.eclipse.jgit.lib.Constants.HEAD; +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.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FS.ExecutionResult; +import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.TemporaryBuffer; +import org.junit.Test; + +public class LinkedWorktreeTest extends RepositoryTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + + try (Git git = new Git(db)) { + git.commit().setMessage("Initial commit").call(); + } + } + + @Test + public void testWeCanReadFromLinkedWorktreeFromBare() throws Exception { + FS fs = db.getFS(); + File directory = trash.getParentFile(); + String dbDirName = db.getWorkTree().getName(); + cloneBare(fs, directory, dbDirName, "bare"); + File bareDirectory = new File(directory, "bare"); + worktreeAddExisting(fs, bareDirectory, "master"); + + File worktreesDir = new File(bareDirectory, "worktrees"); + File masterWorktreesDir = new File(worktreesDir, "master"); + + FileRepository repository = new FileRepository(masterWorktreesDir); + try (Git git = new Git(repository)) { + ObjectId objectId = repository.resolve(HEAD); + assertNotNull(objectId); + + Iterator<RevCommit> log = git.log().all().call().iterator(); + assertTrue(log.hasNext()); + assertTrue("Initial commit".equals(log.next().getShortMessage())); + + // we have reflog entry + // depending on git version we either have one or + // two entries where extra is zeroid entry with + // same message or no message + Collection<ReflogEntry> reflog = git.reflog().call(); + assertNotNull(reflog); + assertTrue(reflog.size() > 0); + ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]); + assertEquals(reflogs[reflogs.length - 1].getComment(), + "reset: moving to HEAD"); + + // index works with file changes + File masterDir = new File(directory, "master"); + File testFile = new File(masterDir, "test"); + + Status status = git.status().call(); + assertTrue(status.getUncommittedChanges().size() == 0); + assertTrue(status.getUntracked().size() == 0); + + JGitTestUtil.write(testFile, "test"); + status = git.status().call(); + assertTrue(status.getUncommittedChanges().size() == 0); + assertTrue(status.getUntracked().size() == 1); + + git.add().addFilepattern("test").call(); + status = git.status().call(); + assertTrue(status.getUncommittedChanges().size() == 1); + assertTrue(status.getUntracked().size() == 0); + } + } + + @Test + public void testWeCanReadFromLinkedWorktreeFromNonBare() throws Exception { + FS fs = db.getFS(); + worktreeAddNew(fs, db.getWorkTree(), "wt"); + + File worktreesDir = new File(db.getDirectory(), "worktrees"); + File masterWorktreesDir = new File(worktreesDir, "wt"); + + FileRepository repository = new FileRepository(masterWorktreesDir); + try (Git git = new Git(repository)) { + ObjectId objectId = repository.resolve(HEAD); + assertNotNull(objectId); + + Iterator<RevCommit> log = git.log().all().call().iterator(); + assertTrue(log.hasNext()); + assertTrue("Initial commit".equals(log.next().getShortMessage())); + + // we have reflog entry + Collection<ReflogEntry> reflog = git.reflog().call(); + assertNotNull(reflog); + assertTrue(reflog.size() > 0); + ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]); + assertEquals(reflogs[reflogs.length - 1].getComment(), + "reset: moving to HEAD"); + + // index works with file changes + File directory = trash.getParentFile(); + File wtDir = new File(directory, "wt"); + File testFile = new File(wtDir, "test"); + + Status status = git.status().call(); + assertTrue(status.getUncommittedChanges().size() == 0); + assertTrue(status.getUntracked().size() == 0); + + JGitTestUtil.write(testFile, "test"); + status = git.status().call(); + assertTrue(status.getUncommittedChanges().size() == 0); + assertTrue(status.getUntracked().size() == 1); + + git.add().addFilepattern("test").call(); + status = git.status().call(); + assertTrue(status.getUncommittedChanges().size() == 1); + assertTrue(status.getUntracked().size() == 0); + } + + } + + private static void cloneBare(FS fs, File directory, String from, String to) throws IOException, InterruptedException { + ProcessBuilder builder = fs.runInShell("git", + new String[] { "clone", "--bare", from, to }); + builder.directory(directory); + builder.environment().put("HOME", fs.userHome().getAbsolutePath()); + StringBuilder input = new StringBuilder(); + ExecutionResult result = fs.execute(builder, new ByteArrayInputStream( + input.toString().getBytes(StandardCharsets.UTF_8))); + String stdOut = toString(result.getStdout()); + String errorOut = toString(result.getStderr()); + assertNotNull(stdOut); + assertNotNull(errorOut); + } + + private static void worktreeAddExisting(FS fs, File directory, String name) throws IOException, InterruptedException { + ProcessBuilder builder = fs.runInShell("git", + new String[] { "worktree", "add", "../" + name, name }); + builder.directory(directory); + builder.environment().put("HOME", fs.userHome().getAbsolutePath()); + StringBuilder input = new StringBuilder(); + ExecutionResult result = fs.execute(builder, new ByteArrayInputStream( + input.toString().getBytes(StandardCharsets.UTF_8))); + String stdOut = toString(result.getStdout()); + String errorOut = toString(result.getStderr()); + assertNotNull(stdOut); + assertNotNull(errorOut); + } + + private static void worktreeAddNew(FS fs, File directory, String name) throws IOException, InterruptedException { + ProcessBuilder builder = fs.runInShell("git", + new String[] { "worktree", "add", "-b", name, "../" + name, "master"}); + builder.directory(directory); + builder.environment().put("HOME", fs.userHome().getAbsolutePath()); + StringBuilder input = new StringBuilder(); + ExecutionResult result = fs.execute(builder, new ByteArrayInputStream( + input.toString().getBytes(StandardCharsets.UTF_8))); + String stdOut = toString(result.getStdout()); + String errorOut = toString(result.getStderr()); + assertNotNull(stdOut); + assertNotNull(errorOut); + } + + private static String toString(TemporaryBuffer b) throws IOException { + return RawParseUtils.decode(b.toByteArray()); + } + +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java index 917b6c3..1ec5067 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -21,6 +21,9 @@ import static org.junit.Assume.assumeTrue; import java.io.File; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Iterator; import java.util.regex.Pattern; @@ -33,6 +36,7 @@ import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.Sets; @@ -45,6 +49,7 @@ import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.GitDateFormatter; import org.eclipse.jgit.util.GitDateFormatter.Format; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.experimental.theories.DataPoints; @@ -76,12 +81,12 @@ public void testMergeInItself() throws Exception { assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); } // no reflog entry written by merge - assertEquals("commit (initial): initial commit", - db + RefDatabase refDb = db.getRefDatabase(); + assertEquals("commit (initial): initial commit", refDb .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("commit (initial): initial commit", - db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("commit (initial): initial commit", refDb + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test @@ -96,10 +101,11 @@ public void testAlreadyUpToDate() throws Exception { assertEquals(second, result.getNewHead()); } // no reflog entry written by merge - assertEquals("commit: second commit", db + assertEquals("commit: second commit", db.getRefDatabase() .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("commit: second commit", db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("commit: second commit", db.getRefDatabase() + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test @@ -117,10 +123,13 @@ public void testFastForward() throws Exception { assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); assertEquals(second, result.getNewHead()); } + RefDatabase refDb = db.getRefDatabase(); assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(Constants.HEAD).getLastEntry().getComment()); + refDb.getReflogReader(Constants.HEAD) + .getLastEntry().getComment()); assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(db.getBranch()).getLastEntry().getComment()); + refDb.getReflogReader(db.getFullBranch()) + .getLastEntry().getComment()); } @Test @@ -140,10 +149,12 @@ public void testFastForwardNoCommit() throws Exception { result.getMergeStatus()); assertEquals(second, result.getNewHead()); } - assertEquals("merge refs/heads/master: Fast-forward", db + RefDatabase refDb = db.getRefDatabase(); + assertEquals("merge refs/heads/master: Fast-forward", refDb .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("merge refs/heads/master: Fast-forward", db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("merge refs/heads/master: Fast-forward", refDb + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test @@ -171,10 +182,12 @@ public void testFastForwardWithFiles() throws Exception { assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); assertEquals(second, result.getNewHead()); } - assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(db.getBranch()).getLastEntry().getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals("merge refs/heads/master: Fast-forward", refDb + .getReflogReader(Constants.HEAD).getLastEntry().getComment()); + assertEquals("merge refs/heads/master: Fast-forward", refDb + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test @@ -229,14 +242,17 @@ public void testMergeSuccessAllStrategies(MergeStrategy mergeStrategy) .include(db.exactRef(R_HEADS + MASTER)).call(); assertEquals(MergeStatus.MERGED, result.getMergeStatus()); } + RefDatabase refDb = db.getRefDatabase(); assertEquals( "merge refs/heads/master: Merge made by " + mergeStrategy.getName() + ".", - db.getReflogReader(Constants.HEAD).getLastEntry().getComment()); + refDb.getReflogReader(Constants.HEAD).getLastEntry() + .getComment()); assertEquals( "merge refs/heads/master: Merge made by " + mergeStrategy.getName() + ".", - db.getReflogReader(db.getBranch()).getLastEntry().getComment()); + refDb.getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Theory @@ -662,14 +678,17 @@ public void testMultipleCreationsSameContent() throws Exception { .setStrategy(MergeStrategy.RESOLVE).call(); assertEquals(MergeStatus.MERGED, result.getMergeStatus()); assertEquals("1\nb(1)\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("merge " + secondCommit.getId().getName() - + ": Merge made by resolve.", db - .getReflogReader(Constants.HEAD) - .getLastEntry().getComment()); - assertEquals("merge " + secondCommit.getId().getName() - + ": Merge made by resolve.", db - .getReflogReader(db.getBranch()) - .getLastEntry().getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals( + "merge " + secondCommit.getId().getName() + + ": Merge made by resolve.", + refDb.getReflogReader(Constants.HEAD).getLastEntry() + .getComment()); + assertEquals( + "merge " + secondCommit.getId().getName() + + ": Merge made by resolve.", + refDb.getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } } @@ -2086,6 +2105,94 @@ public void testMergeConflictWithMessageAndCommentCharAuto() } } + @Test + public void testMergeCaseInsensitiveRename() throws Exception { + Assume.assumeTrue( + "Test makes only sense on a case-insensitive file system", + db.isWorkTreeCaseInsensitive()); + try (Git git = new Git(db)) { + writeTrashFile("a", "aaa"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + // "Rename" "a" to "A" + git.rm().addFilepattern("a").call(); + writeTrashFile("A", "aaa"); + git.add().addFilepattern("A").call(); + RevCommit master = git.commit().setMessage("rename to A").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("b", "bbb"); + git.add().addFilepattern("b").call(); + git.commit().setMessage("side").call(); + + // Merge master into side + MergeResult result = git.merge().include(master) + .setStrategy(MergeStrategy.RECURSIVE).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + assertTrue(new File(db.getWorkTree(), "A").isFile()); + // Double check + boolean found = true; + try (DirectoryStream<Path> dir = Files + .newDirectoryStream(db.getWorkTree().toPath())) { + for (Path p : dir) { + found = "A".equals(p.getFileName().toString()); + if (found) { + break; + } + } + } + assertTrue(found); + } + } + + @Test + public void testMergeCaseInsensitiveRenameConflict() throws Exception { + Assume.assumeTrue( + "Test makes only sense on a case-insensitive file system", + db.isWorkTreeCaseInsensitive()); + try (Git git = new Git(db)) { + writeTrashFile("a", "aaa"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + // "Rename" "a" to "A" and change it + git.rm().addFilepattern("a").call(); + writeTrashFile("A", "yyy"); + git.add().addFilepattern("A").call(); + RevCommit master = git.commit().setMessage("rename to A").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "xxx"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("side").call(); + + // Merge master into side + MergeResult result = git.merge().include(master) + .setStrategy(MergeStrategy.RECURSIVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + File a = new File(db.getWorkTree(), "A"); + assertTrue(a.isFile()); + // Double check + boolean found = true; + try (DirectoryStream<Path> dir = Files + .newDirectoryStream(db.getWorkTree().toPath())) { + for (Path p : dir) { + found = "A".equals(p.getFileName().toString()); + if (found) { + break; + } + } + } + assertTrue(found); + assertEquals(1, result.getConflicts().size()); + assertTrue(result.getConflicts().containsKey("a")); + checkFile(a, "yyy"); + } + } + private static void setExecutable(Git git, String path, boolean executable) { FS.DETECTED.setExecute( new File(git.getRepository().getWorkTree(), path), executable);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java index 12300b3..6d5e45c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
@@ -21,6 +21,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.util.Map; import java.util.concurrent.Callable; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; @@ -29,6 +30,7 @@ import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.IndexDiff.StageState; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; @@ -117,6 +119,7 @@ public void testPullMerge() throws Exception { + db.getWorkTree().getAbsolutePath(); assertEquals(message, mergeCommit.getShortMessage()); } + assertTrue(target.status().call().isClean()); } @Test @@ -153,6 +156,10 @@ public void testPullConflict() throws Exception { assertFileContentsEqual(targetFile, result); assertEquals(RepositoryState.MERGING, target.getRepository() .getRepositoryState()); + Status status = target.status().call(); + Map<String, StageState> conflicting = status.getConflictingStageState(); + assertEquals(1, conflicting.size()); + assertEquals(StageState.BOTH_MODIFIED, conflicting.get("SomeFile.txt")); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java index 70e990d..d1696d6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
@@ -22,6 +22,7 @@ import java.io.PrintStream; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.Properties; import org.eclipse.jgit.api.errors.DetachedHeadException; @@ -1146,7 +1147,7 @@ public void testPushAfterGC() throws Exception { RevCommit commit2 = git2.commit().setMessage("adding a").call(); // run a gc to ensure we have a bitmap index - Properties res = git1.gc().setExpire(null).call(); + Properties res = git1.gc().setExpire((Instant) null).call(); assertEquals(8, res.size()); // create another commit so we have something else to push
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java index 02e3a2e..4c8cf06 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -24,6 +24,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -55,6 +57,7 @@ import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RebaseTodoLine; import org.eclipse.jgit.lib.RebaseTodoLine.Action; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.lib.RepositoryState; @@ -131,11 +134,12 @@ public void testFastForwardWithNewFile() throws Exception { checkFile(file2, "file2"); assertEquals(Status.FAST_FORWARD, res.getStatus()); - List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD) + RefDatabase refDb = db.getRefDatabase(); + List<ReflogEntry> headLog = refDb.getReflogReader(Constants.HEAD) .getReverseEntries(); - List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic") + List<ReflogEntry> topicLog = refDb.getReflogReader("refs/heads/topic") .getReverseEntries(); - List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master") + List<ReflogEntry> masterLog = refDb.getReflogReader("refs/heads/master") .getReverseEntries(); assertEquals("rebase finished: returning to refs/heads/topic", headLog .get(0).getComment()); @@ -177,11 +181,12 @@ public void testFastForwardWithMultipleCommits() throws Exception { checkFile(file2, "file2 new content"); assertEquals(Status.FAST_FORWARD, res.getStatus()); - List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD) + RefDatabase refDb = db.getRefDatabase(); + List<ReflogEntry> headLog = refDb.getReflogReader(Constants.HEAD) .getReverseEntries(); - List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic") + List<ReflogEntry> topicLog = refDb.getReflogReader("refs/heads/topic") .getReverseEntries(); - List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master") + List<ReflogEntry> masterLog = refDb.getReflogReader("refs/heads/master") .getReverseEntries(); assertEquals("rebase finished: returning to refs/heads/topic", headLog .get(0).getComment()); @@ -445,13 +450,14 @@ public void testRebaseShouldIgnoreMergeCommits() assertEquals(a, rw.next()); } - List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD) + RefDatabase refDb = db.getRefDatabase(); + List<ReflogEntry> headLog = refDb.getReflogReader(Constants.HEAD) .getReverseEntries(); - List<ReflogEntry> sideLog = db.getReflogReader("refs/heads/side") + List<ReflogEntry> sideLog = refDb.getReflogReader("refs/heads/side") .getReverseEntries(); - List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic") + List<ReflogEntry> topicLog = refDb.getReflogReader("refs/heads/topic") .getReverseEntries(); - List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master") + List<ReflogEntry> masterLog = refDb.getReflogReader("refs/heads/master") .getReverseEntries(); assertEquals("rebase finished: returning to refs/heads/topic", headLog .get(0).getComment()); @@ -766,9 +772,10 @@ public void testRebaseParentOntoHeadShouldBeUptoDate() throws Exception { RebaseResult result = git.rebase().setUpstream(parent).call(); assertEquals(Status.UP_TO_DATE, result.getStatus()); - assertEquals(2, db.getReflogReader(Constants.HEAD).getReverseEntries() - .size()); - assertEquals(2, db.getReflogReader("refs/heads/master") + RefDatabase refDb = db.getRefDatabase(); + assertEquals(2, refDb.getReflogReader(Constants.HEAD) + .getReverseEntries().size()); + assertEquals(2, refDb.getReflogReader("refs/heads/master") .getReverseEntries().size()); } @@ -784,9 +791,10 @@ public void testUpToDate() throws Exception { RebaseResult res = git.rebase().setUpstream(first).call(); assertEquals(Status.UP_TO_DATE, res.getStatus()); - assertEquals(1, db.getReflogReader(Constants.HEAD).getReverseEntries() - .size()); - assertEquals(1, db.getReflogReader("refs/heads/master") + RefDatabase refDb = db.getRefDatabase(); + assertEquals(1, refDb.getReflogReader(Constants.HEAD) + .getReverseEntries().size()); + assertEquals(1, refDb.getReflogReader("refs/heads/master") .getReverseEntries().size()); } @@ -844,11 +852,12 @@ public void testConflictFreeWithSingleFile() throws Exception { db.resolve(Constants.HEAD)).getParent(0)); } assertEquals(origHead, db.readOrigHead()); - List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD) + RefDatabase refDb = db.getRefDatabase(); + List<ReflogEntry> headLog = refDb.getReflogReader(Constants.HEAD) .getReverseEntries(); - List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic") + List<ReflogEntry> topicLog = refDb.getReflogReader("refs/heads/topic") .getReverseEntries(); - List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master") + List<ReflogEntry> masterLog = refDb.getReflogReader("refs/heads/master") .getReverseEntries(); assertEquals(2, masterLog.size()); assertEquals(3, topicLog.size()); @@ -896,8 +905,8 @@ public void testDetachedHead() throws Exception { db.resolve(Constants.HEAD)).getParent(0)); } - List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD) - .getReverseEntries(); + List<ReflogEntry> headLog = db.getRefDatabase() + .getReflogReader(Constants.HEAD).getReverseEntries(); assertEquals(8, headLog.size()); assertEquals("rebase: change file1 in topic", headLog.get(0) .getComment()); @@ -1603,7 +1612,7 @@ public void testStopOnConflictFileCreationAndDeletion() throws Exception { public void testAuthorScriptConverter() throws Exception { // -1 h timezone offset PersonIdent ident = new PersonIdent("Author name", "a.mail@some.com", - 123456789123L, -60); + Instant.ofEpochMilli(123456789123L), ZoneOffset.ofHours(-1)); String convertedAuthor = git.rebase().toAuthorScript(ident); String[] lines = convertedAuthor.split("\n"); assertEquals("GIT_AUTHOR_NAME='Author name'", lines[0]); @@ -1615,12 +1624,14 @@ public void testAuthorScriptConverter() throws Exception { assertEquals(ident.getName(), parsedIdent.getName()); assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress()); // this is rounded to the last second - assertEquals(123456789000L, parsedIdent.getWhen().getTime()); - assertEquals(ident.getTimeZoneOffset(), parsedIdent.getTimeZoneOffset()); + assertEquals(123456789000L, + parsedIdent.getWhenAsInstant().toEpochMilli()); + assertEquals(ident.getZoneId(), parsedIdent.getZoneId()); // + 9.5h timezone offset ident = new PersonIdent("Author name", "a.mail@some.com", - 123456789123L, +570); + Instant.ofEpochMilli(123456789123L), + ZoneOffset.ofHoursMinutes(9, 30)); convertedAuthor = git.rebase().toAuthorScript(ident); lines = convertedAuthor.split("\n"); assertEquals("GIT_AUTHOR_NAME='Author name'", lines[0]); @@ -1631,8 +1642,9 @@ public void testAuthorScriptConverter() throws Exception { convertedAuthor.getBytes(UTF_8)); assertEquals(ident.getName(), parsedIdent.getName()); assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress()); - assertEquals(123456789000L, parsedIdent.getWhen().getTime()); - assertEquals(ident.getTimeZoneOffset(), parsedIdent.getTimeZoneOffset()); + assertEquals(123456789000L, + parsedIdent.getWhenAsInstant().toEpochMilli()); + assertEquals(ident.getZoneId(), parsedIdent.getZoneId()); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java index 534ebd9..add5886 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RenameBranchCommandTest.java
@@ -118,23 +118,21 @@ public void renameBranchSingleConfigValue() throws Exception { String branch = "b1"; assertEquals(BranchRebaseMode.REBASE, - config.getEnum(BranchRebaseMode.values(), - ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER, - ConfigConstants.CONFIG_KEY_REBASE, + config.getEnum(ConfigConstants.CONFIG_BRANCH_SECTION, + Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE)); assertNull(config.getEnum(BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, branch, - ConfigConstants.CONFIG_KEY_REBASE, null)); + ConfigConstants.CONFIG_KEY_REBASE)); assertNotNull(git.branchRename().setNewName(branch).call()); config = git.getRepository().getConfig(); assertNull(config.getEnum(BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER, - ConfigConstants.CONFIG_KEY_REBASE, null)); + ConfigConstants.CONFIG_KEY_REBASE)); assertEquals(BranchRebaseMode.REBASE, - config.getEnum(BranchRebaseMode.values(), - ConfigConstants.CONFIG_BRANCH_SECTION, branch, + config.getEnum(ConfigConstants.CONFIG_BRANCH_SECTION, branch, ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE)); } @@ -170,13 +168,12 @@ public void renameBranchMultipleConfigValues() throws Exception { String branch = "b1"; assertEquals(BranchRebaseMode.REBASE, - config.getEnum(BranchRebaseMode.values(), - ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER, - ConfigConstants.CONFIG_KEY_REBASE, + config.getEnum(ConfigConstants.CONFIG_BRANCH_SECTION, + Constants.MASTER, ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE)); assertNull(config.getEnum(BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, branch, - ConfigConstants.CONFIG_KEY_REBASE, null)); + ConfigConstants.CONFIG_KEY_REBASE)); assertTrue(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER, ConfigConstants.CONFIG_KEY_MERGE, true)); assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, @@ -187,10 +184,9 @@ public void renameBranchMultipleConfigValues() throws Exception { config = git.getRepository().getConfig(); assertNull(config.getEnum(BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, Constants.MASTER, - ConfigConstants.CONFIG_KEY_REBASE, null)); + ConfigConstants.CONFIG_KEY_REBASE)); assertEquals(BranchRebaseMode.REBASE, - config.getEnum(BranchRebaseMode.values(), - ConfigConstants.CONFIG_BRANCH_SECTION, branch, + config.getEnum(ConfigConstants.CONFIG_BRANCH_SECTION, branch, ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE)); assertFalse(config.getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java index 8a479a0..99873e1 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -36,11 +36,13 @@ import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.FileUtils; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; public class ResetCommandTest extends RepositoryTestCase { @@ -554,46 +556,73 @@ public void testHardResetOnUnbornBranch() throws Exception { assertNull(db.resolve(Constants.HEAD)); } + @Test + public void testHardResetFileMode() throws Exception { + Assume.assumeTrue("Test must be able to set executable bit", + db.getFS().supportsExecute()); + git = new Git(db); + File a = writeTrashFile("a.txt", "aaa"); + File b = writeTrashFile("b.txt", "bbb"); + db.getFS().setExecute(b, true); + assertFalse(db.getFS().canExecute(a)); + assertTrue(db.getFS().canExecute(b)); + git.add().addFilepattern("a.txt").addFilepattern("b.txt").call(); + RevCommit commit = git.commit().setMessage("files created").call(); + db.getFS().setExecute(a, true); + db.getFS().setExecute(b, false); + assertTrue(db.getFS().canExecute(a)); + assertFalse(db.getFS().canExecute(b)); + git.add().addFilepattern("a.txt").addFilepattern("b.txt").call(); + git.commit().setMessage("change exe bits").call(); + Ref ref = git.reset().setRef(commit.getName()).setMode(HARD).call(); + assertSameAsHead(ref); + assertEquals(commit.getId(), ref.getObjectId()); + assertFalse(db.getFS().canExecute(a)); + assertTrue(db.getFS().canExecute(b)); + } + private void assertReflog(ObjectId prevHead, ObjectId head) throws IOException { // Check the reflog for HEAD - String actualHeadMessage = db.getReflogReader(Constants.HEAD) + RefDatabase refDb = db.getRefDatabase(); + String actualHeadMessage = refDb.getReflogReader(Constants.HEAD) .getLastEntry().getComment(); String expectedHeadMessage = head.getName() + ": updating HEAD"; assertEquals(expectedHeadMessage, actualHeadMessage); - assertEquals(head.getName(), db.getReflogReader(Constants.HEAD) + assertEquals(head.getName(), refDb.getReflogReader(Constants.HEAD) .getLastEntry().getNewId().getName()); - assertEquals(prevHead.getName(), db.getReflogReader(Constants.HEAD) + assertEquals(prevHead.getName(), refDb.getReflogReader(Constants.HEAD) .getLastEntry().getOldId().getName()); // The reflog for master contains the same as the one for HEAD - String actualMasterMessage = db.getReflogReader("refs/heads/master") + String actualMasterMessage = refDb.getReflogReader("refs/heads/master") .getLastEntry().getComment(); String expectedMasterMessage = head.getName() + ": updating HEAD"; // yes! assertEquals(expectedMasterMessage, actualMasterMessage); - assertEquals(head.getName(), db.getReflogReader(Constants.HEAD) + assertEquals(head.getName(), refDb.getReflogReader(Constants.HEAD) .getLastEntry().getNewId().getName()); - assertEquals(prevHead.getName(), db - .getReflogReader("refs/heads/master").getLastEntry().getOldId() - .getName()); + assertEquals(prevHead.getName(), + refDb.getReflogReader("refs/heads/master").getLastEntry() + .getOldId().getName()); } private void assertReflogDisabled(ObjectId head) throws IOException { + RefDatabase refDb = db.getRefDatabase(); // Check the reflog for HEAD - String actualHeadMessage = db.getReflogReader(Constants.HEAD) + String actualHeadMessage = refDb.getReflogReader(Constants.HEAD) .getLastEntry().getComment(); String expectedHeadMessage = "commit: adding a.txt and dir/b.txt"; assertEquals(expectedHeadMessage, actualHeadMessage); - assertEquals(head.getName(), db.getReflogReader(Constants.HEAD) + assertEquals(head.getName(), refDb.getReflogReader(Constants.HEAD) .getLastEntry().getOldId().getName()); // The reflog for master contains the same as the one for HEAD - String actualMasterMessage = db.getReflogReader("refs/heads/master") + String actualMasterMessage = refDb.getReflogReader("refs/heads/master") .getLastEntry().getComment(); String expectedMasterMessage = "commit: adding a.txt and dir/b.txt"; assertEquals(expectedMasterMessage, actualMasterMessage); - assertEquals(head.getName(), db.getReflogReader(Constants.HEAD) + assertEquals(head.getName(), refDb.getReflogReader(Constants.HEAD) .getLastEntry().getOldId().getName()); } /**
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java index 4ebe994..89fdb32 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Robin Rosenberg and others + * Copyright (C) 2011, 2024 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 @@ -29,6 +29,7 @@ import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; @@ -59,7 +60,9 @@ public void testRevert() throws IOException, JGitInternalException, writeTrashFile("a", "first line\nsecond line\nthird line\nfourth line\n"); git.add().addFilepattern("a").call(); - RevCommit fixingA = git.commit().setMessage("fixed a").call(); + // Commit message with a non-empty second line on purpose + RevCommit fixingA = git.commit().setMessage("fixed a\nsecond line") + .call(); writeTrashFile("b", "first line\n"); git.add().addFilepattern("b").call(); @@ -78,16 +81,18 @@ public void testRevert() throws IOException, JGitInternalException, + "This reverts commit " + fixingA.getId().getName() + ".\n"; assertEquals(expectedMessage, revertCommit.getFullMessage()); assertEquals("fixed b", history.next().getFullMessage()); - assertEquals("fixed a", history.next().getFullMessage()); + assertEquals("fixed a\nsecond line", + history.next().getFullMessage()); assertEquals("enlarged a", history.next().getFullMessage()); assertEquals("create b", history.next().getFullMessage()); assertEquals("create a", history.next().getFullMessage()); assertFalse(history.hasNext()); - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue(reader.getLastEntry().getComment() .startsWith("revert: Revert \"")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue(reader.getLastEntry().getComment() .startsWith("revert: Revert \"")); } @@ -167,10 +172,11 @@ public void testRevertMultiple() throws IOException, JGitInternalException, assertEquals("add first", history.next().getFullMessage()); assertFalse(history.hasNext()); - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue(reader.getLastEntry().getComment() .startsWith("revert: Revert \"")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue(reader.getLastEntry().getComment() .startsWith("revert: Revert \"")); } @@ -220,10 +226,11 @@ public void testRevertMultipleWithFail() throws IOException, assertEquals("add first", history.next().getFullMessage()); assertFalse(history.hasNext()); - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue(reader.getLastEntry().getComment() .startsWith("revert: Revert \"")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue(reader.getLastEntry().getComment() .startsWith("revert: Revert \"")); } @@ -428,12 +435,13 @@ private void doRevertAndCheckResult(final Git git, assertEquals(RepositoryState.SAFE, db.getRepositoryState()); if (reason == null) { - ReflogReader reader = db.getReflogReader(Constants.HEAD); - assertTrue(reader.getLastEntry().getComment() - .startsWith("revert: ")); - reader = db.getReflogReader(db.getBranch()); - assertTrue(reader.getLastEntry().getComment() - .startsWith("revert: ")); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); + assertTrue( + reader.getLastEntry().getComment().startsWith("revert: ")); + reader = refDb.getReflogReader(db.getFullBranch()); + assertTrue( + reader.getLastEntry().getComment().startsWith("revert: ")); } } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerMissingPermissionsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerMissingPermissionsTest.java deleted file mode 100644 index d0fbdbd..0000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerMissingPermissionsTest.java +++ /dev/null
@@ -1,126 +0,0 @@ -/* - * Copyright (c) 2019 Alex Jitianu <alex_jitianu@sync.ro> 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.api; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.Policy; -import java.util.Collections; - -import org.eclipse.jgit.junit.RepositoryTestCase; -import org.eclipse.jgit.util.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests that using a SecurityManager does not result in errors logged. - */ -public class SecurityManagerMissingPermissionsTest extends RepositoryTestCase { - - /** - * Collects all logging sent to the logging system. - */ - private final ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); - - private SecurityManager originalSecurityManager; - - private PrintStream defaultErrorOutput; - - @Override - @Before - public void setUp() throws Exception { - originalSecurityManager = System.getSecurityManager(); - - // slf4j-simple logs to System.err, redirect it to enable asserting - // logged errors - defaultErrorOutput = System.err; - System.setErr(new PrintStream(errorOutput)); - - refreshPolicyAllPermission(Policy.getPolicy()); - System.setSecurityManager(new SecurityManager()); - super.setUp(); - } - - /** - * If a SecurityManager is active a lot of {@link java.io.FilePermission} - * errors are thrown and logged while initializing a repository. - * - * @throws Exception - */ - @Test - public void testCreateNewRepos_MissingPermissions() throws Exception { - File wcTree = new File(getTemporaryDirectory(), - "CreateNewRepositoryTest_testCreateNewRepos"); - - File marker = new File(getTemporaryDirectory(), "marker"); - Files.write(marker.toPath(), Collections.singletonList("Can write")); - assertTrue("Can write in test directory", marker.isFile()); - FileUtils.delete(marker); - assertFalse("Can delete in test direcory", marker.exists()); - - Git git = Git.init().setBare(false) - .setDirectory(new File(wcTree.getAbsolutePath())).call(); - - addRepoToClose(git.getRepository()); - - assertEquals("", errorOutput.toString()); - } - - @Override - @After - public void tearDown() throws Exception { - System.setSecurityManager(originalSecurityManager); - System.setErr(defaultErrorOutput); - super.tearDown(); - } - - /** - * Refresh the Java Security Policy. - * - * @param policy - * the policy object - * - * @throws IOException - * if the temporary file that contains the policy could not be - * created - */ - private static void refreshPolicyAllPermission(Policy policy) - throws IOException { - // Starting with an all permissions policy. - String policyString = "grant { permission java.security.AllPermission; };"; - - // Do not use TemporaryFilesFactory, it will create a dependency cycle - Path policyFile = Files.createTempFile("testpolicy", ".txt"); - - try { - Files.write(policyFile, Collections.singletonList(policyString)); - System.setProperty("java.security.policy", - policyFile.toUri().toURL().toString()); - policy.refresh(); - } finally { - try { - Files.delete(policyFile); - } catch (IOException e) { - // Do not log; the test tests for no logging having occurred - e.printStackTrace(); - } - } - } - -}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java deleted file mode 100644 index 2b930a1..0000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java +++ /dev/null
@@ -1,173 +0,0 @@ -/* - * Copyright (C) 2019 Nail Samatov <sanail@yandex.ru> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.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.io.FilePermission; -import java.io.IOException; -import java.lang.reflect.ReflectPermission; -import java.nio.file.Files; -import java.security.Permission; -import java.security.SecurityPermission; -import java.util.ArrayList; -import java.util.List; -import java.util.PropertyPermission; -import java.util.logging.LoggingPermission; - -import javax.security.auth.AuthPermission; - -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.junit.JGitTestUtil; -import org.eclipse.jgit.junit.MockSystemReader; -import org.eclipse.jgit.junit.SeparateClassloaderTestRunner; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.treewalk.TreeWalk; -import org.eclipse.jgit.util.FileUtils; -import org.eclipse.jgit.util.SystemReader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * <p> - * Tests if jgit works if SecurityManager is enabled. - * </p> - * - * <p> - * Note: JGit's classes shouldn't be used before SecurityManager is configured. - * If you use some JGit's class before SecurityManager is replaced then part of - * the code can be invoked outside of our custom SecurityManager and this test - * becomes useless. - * </p> - * - * <p> - * For example the class {@link org.eclipse.jgit.util.FS} is used widely in jgit - * sources. It contains DETECTED static field. At the first usage of the class - * FS the field DETECTED is initialized and during initialization many system - * operations that SecurityManager can forbid are invoked. - * </p> - * - * <p> - * For this reason this test doesn't extend LocalDiskRepositoryTestCase (it uses - * JGit's classes in setUp() method) and other JGit's utility classes. It's done - * to affect SecurityManager as less as possible. - * </p> - * - * <p> - * We use SeparateClassloaderTestRunner to isolate FS.DETECTED field - * initialization between different tests run. - * </p> - */ -@RunWith(SeparateClassloaderTestRunner.class) -public class SecurityManagerTest { - private File root; - - private SecurityManager originalSecurityManager; - - private List<Permission> permissions = new ArrayList<>(); - - @Before - public void setUp() throws Exception { - // Create working directory - SystemReader.setInstance(new MockSystemReader()); - root = Files.createTempDirectory("jgit-security").toFile(); - - // Add system permissions - permissions.add(new RuntimePermission("*")); - permissions.add(new SecurityPermission("*")); - permissions.add(new AuthPermission("*")); - permissions.add(new ReflectPermission("*")); - permissions.add(new PropertyPermission("*", "read,write")); - permissions.add(new LoggingPermission("control", null)); - - permissions.add(new FilePermission( - System.getProperty("java.home") + "/-", "read")); - - String tempDir = System.getProperty("java.io.tmpdir"); - permissions.add(new FilePermission(tempDir, "read,write,delete")); - permissions - .add(new FilePermission(tempDir + "/-", "read,write,delete")); - - // Add permissions to dependent jar files. - String classPath = System.getProperty("java.class.path"); - if (classPath != null) { - for (String path : classPath.split(File.pathSeparator)) { - permissions.add(new FilePermission(path, "read")); - } - } - // Add permissions to jgit class files. - String jgitSourcesRoot = new File(System.getProperty("user.dir")) - .getParent(); - permissions.add(new FilePermission(jgitSourcesRoot + "/-", "read")); - - // Add permissions to working dir for jgit. Our git repositories will be - // initialized and cloned here. - permissions.add(new FilePermission(root.getPath() + "/-", - "read,write,delete,execute")); - - // Replace Security Manager - originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new SecurityManager() { - - @Override - public void checkPermission(Permission requested) { - for (Permission permission : permissions) { - if (permission.implies(requested)) { - return; - } - } - - super.checkPermission(requested); - } - }); - } - - @After - public void tearDown() throws Exception { - System.setSecurityManager(originalSecurityManager); - - // Note: don't use this method before security manager is replaced in - // setUp() method. The method uses FS.DETECTED internally and can affect - // the test. - FileUtils.delete(root, FileUtils.RECURSIVE | FileUtils.RETRY); - } - - @Test - public void testInitAndClone() throws IOException, GitAPIException { - File remote = new File(root, "remote"); - File local = new File(root, "local"); - - try (Git git = Git.init().setDirectory(remote).call()) { - JGitTestUtil.write(new File(remote, "hello.txt"), "Hello world!"); - git.add().addFilepattern(".").call(); - git.commit().setMessage("Initial commit").call(); - } - - try (Git git = Git.cloneRepository().setURI(remote.toURI().toString()) - .setDirectory(local).call()) { - assertTrue(new File(local, ".git").exists()); - - JGitTestUtil.write(new File(local, "hi.txt"), "Hi!"); - git.add().addFilepattern(".").call(); - RevCommit commit1 = git.commit().setMessage("Commit on local repo") - .call(); - assertEquals("Commit on local repo", commit1.getFullMessage()); - assertNotNull(TreeWalk.forPath(git.getRepository(), "hello.txt", - commit1.getTree())); - } - - } - -}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java index 5d0ab05..18cd21a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
@@ -409,8 +409,8 @@ public void refLogIncludesCommitMessage() throws Exception { assertEquals("content", read(committedFile)); validateStashedCommit(stashed); - ReflogReader reader = git.getRepository().getReflogReader( - Constants.R_STASH); + ReflogReader reader = git.getRepository().getRefDatabase() + .getReflogReader(Constants.R_STASH); ReflogEntry entry = reader.getLastEntry(); assertNotNull(entry); assertEquals(ObjectId.zeroId(), entry.getOldId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java index c81731d..d937579 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java
@@ -92,8 +92,8 @@ public void dropSingleStashedCommit() throws Exception { stashRef = git.getRepository().exactRef(Constants.R_STASH); assertNull(stashRef); - ReflogReader reader = git.getRepository().getReflogReader( - Constants.R_STASH); + ReflogReader reader = git.getRepository().getRefDatabase() + .getReflogReader(Constants.R_STASH); assertNull(reader); } @@ -120,8 +120,8 @@ public void dropAll() throws Exception { assertNull(git.stashDrop().setAll(true).call()); assertNull(git.getRepository().exactRef(Constants.R_STASH)); - ReflogReader reader = git.getRepository().getReflogReader( - Constants.R_STASH); + ReflogReader reader = git.getRepository().getRefDatabase() + .getReflogReader(Constants.R_STASH); assertNull(reader); } @@ -150,8 +150,8 @@ public void dropFirstStashedCommit() throws Exception { assertNotNull(stashRef); assertEquals(firstStash, stashRef.getObjectId()); - ReflogReader reader = git.getRepository().getReflogReader( - Constants.R_STASH); + ReflogReader reader = git.getRepository().getRefDatabase() + .getReflogReader(Constants.R_STASH); List<ReflogEntry> entries = reader.getReverseEntries(); assertEquals(1, entries.size()); assertEquals(ObjectId.zeroId(), entries.get(0).getOldId()); @@ -192,8 +192,8 @@ public void dropMiddleStashCommit() throws Exception { assertNotNull(stashRef); assertEquals(thirdStash, stashRef.getObjectId()); - ReflogReader reader = git.getRepository().getReflogReader( - Constants.R_STASH); + ReflogReader reader = git.getRepository().getRefDatabase() + .getReflogReader(Constants.R_STASH); List<ReflogEntry> entries = reader.getReverseEntries(); assertEquals(2, entries.size()); assertEquals(ObjectId.zeroId(), entries.get(1).getOldId()); @@ -250,8 +250,8 @@ public void dropBoundaryStashedCommits() throws Exception { assertNotNull(stashRef); assertEquals(thirdStash, stashRef.getObjectId()); - ReflogReader reader = git.getRepository().getReflogReader( - Constants.R_STASH); + ReflogReader reader = git.getRepository().getRefDatabase() + .getReflogReader(Constants.R_STASH); List<ReflogEntry> entries = reader.getReverseEntries(); assertEquals(2, entries.size()); assertEquals(ObjectId.zeroId(), entries.get(1).getOldId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java index f47f447..c2c06b2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
@@ -23,20 +23,22 @@ /** Unit tests of {@link BlameGenerator}. */ public class BlameGeneratorTest extends RepositoryTestCase { + private static final String FILE = "file.txt"; + @Test public void testBoundLineDelete() throws Exception { try (Git git = new Git(db)) { String[] content1 = new String[] { "first", "second" }; - writeTrashFile("file.txt", join(content1)); - git.add().addFilepattern("file.txt").call(); + writeTrashFile(FILE, join(content1)); + git.add().addFilepattern(FILE).call(); RevCommit c1 = git.commit().setMessage("create file").call(); String[] content2 = new String[] { "third", "first", "second" }; - writeTrashFile("file.txt", join(content2)); - git.add().addFilepattern("file.txt").call(); + writeTrashFile(FILE, join(content2)); + git.add().addFilepattern(FILE).call(); RevCommit c2 = git.commit().setMessage("create file").call(); - try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) { + try (BlameGenerator generator = new BlameGenerator(db, FILE)) { generator.push(null, db.resolve(Constants.HEAD)); assertEquals(3, generator.getResultContents().size()); @@ -47,7 +49,7 @@ public void testBoundLineDelete() throws Exception { assertEquals(1, generator.getResultEnd()); assertEquals(0, generator.getSourceStart()); assertEquals(1, generator.getSourceEnd()); - assertEquals("file.txt", generator.getSourcePath()); + assertEquals(FILE, generator.getSourcePath()); assertTrue(generator.next()); assertEquals(c1, generator.getSourceCommit()); @@ -56,7 +58,7 @@ public void testBoundLineDelete() throws Exception { assertEquals(3, generator.getResultEnd()); assertEquals(0, generator.getSourceStart()); assertEquals(2, generator.getSourceEnd()); - assertEquals("file.txt", generator.getSourcePath()); + assertEquals(FILE, generator.getSourcePath()); assertFalse(generator.next()); } @@ -87,7 +89,8 @@ public void testRenamedBoundLineDelete() throws Exception { git.add().addFilepattern(FILENAME_2).call(); RevCommit c2 = git.commit().setMessage("change file2").call(); - try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) { + try (BlameGenerator generator = new BlameGenerator(db, + FILENAME_2)) { generator.push(null, db.resolve(Constants.HEAD)); assertEquals(3, generator.getResultContents().size()); @@ -113,7 +116,8 @@ public void testRenamedBoundLineDelete() throws Exception { } // and test again with other BlameGenerator API: - try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) { + try (BlameGenerator generator = new BlameGenerator(db, + FILENAME_2)) { generator.push(null, db.resolve(Constants.HEAD)); BlameResult result = generator.computeBlameResult(); @@ -136,21 +140,21 @@ public void testLinesAllDeletedShortenedWalk() throws Exception { try (Git git = new Git(db)) { String[] content1 = new String[] { "first", "second", "third" }; - writeTrashFile("file.txt", join(content1)); - git.add().addFilepattern("file.txt").call(); + writeTrashFile(FILE, join(content1)); + git.add().addFilepattern(FILE).call(); git.commit().setMessage("create file").call(); String[] content2 = new String[] { "" }; - writeTrashFile("file.txt", join(content2)); - git.add().addFilepattern("file.txt").call(); + writeTrashFile(FILE, join(content2)); + git.add().addFilepattern(FILE).call(); git.commit().setMessage("create file").call(); - writeTrashFile("file.txt", join(content1)); - git.add().addFilepattern("file.txt").call(); + writeTrashFile(FILE, join(content1)); + git.add().addFilepattern(FILE).call(); RevCommit c3 = git.commit().setMessage("create file").call(); - try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) { + try (BlameGenerator generator = new BlameGenerator(db, FILE)) { generator.push(null, db.resolve(Constants.HEAD)); assertEquals(3, generator.getResultContents().size());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java index 7fb98ec..c41dd81 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
@@ -584,7 +584,7 @@ private void setupRepo( } if (infoAttributesContent != null) { - File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES); + File f = new File(db.getCommonDirectory(), Constants.INFO_ATTRIBUTES); write(f, infoAttributesContent); } config.save();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java index f23469e..35b9533 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
@@ -26,6 +26,7 @@ import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.TreeWalk; import org.junit.Before; import org.junit.Test; @@ -230,10 +231,10 @@ private void assertAttributesNode(TreeWalk walk, String pathName, else { Attributes entryAttributes = new Attributes(); - new AttributesHandler(walk).mergeAttributes(attributesNode, - pathName, - false, - entryAttributes); + new AttributesHandler(walk, + () -> walk.getTree(CanonicalTreeParser.class)) + .mergeAttributes(attributesNode, pathName, false, + entryAttributes); if (nodeAttrs != null && !nodeAttrs.isEmpty()) { for (Attribute attribute : nodeAttrs) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java index 1fcfbaf..dbbcb75 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
@@ -20,6 +20,7 @@ import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.TreeWalk; import org.junit.After; import org.junit.Test; @@ -156,8 +157,9 @@ public void testDoubleAsteriskAtEnd() throws IOException { private void assertAttribute(String path, AttributesNode node, Attributes attrs) throws IOException { Attributes attributes = new Attributes(); - new AttributesHandler(DUMMY_WALK).mergeAttributes(node, path, false, - attributes); + new AttributesHandler(DUMMY_WALK, + () -> DUMMY_WALK.getTree(CanonicalTreeParser.class)) + .mergeAttributes(node, path, false, attributes); assertEquals(attrs, attributes); }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java index 7b573e1..c6c9138 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
@@ -26,6 +26,7 @@ import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; @@ -194,9 +195,10 @@ private void assertAttributesNode(TreeWalk walk, String pathName, else { Attributes entryAttributes = new Attributes(); - new AttributesHandler(walk).mergeAttributes(attributesNode, - pathName, false, - entryAttributes); + new AttributesHandler(walk, + () -> walk.getTree(CanonicalTreeParser.class)) + .mergeAttributes(attributesNode, pathName, false, + entryAttributes); if (nodeAttrs != null && !nodeAttrs.isEmpty()) { for (Attribute attribute : nodeAttrs) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java index 009ca8a..ac30c6c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/merge/MergeGitAttributeTest.java
@@ -268,6 +268,51 @@ public void mergeTextualFile_SetBinaryMerge_Conflict() } @Test + public void mergeTextualFile_SetUnionMerge() throws NoWorkTreeException, + NoFilepatternException, GitAPIException, IOException { + try (Git git = createRepositoryBinaryConflict(g -> { + try { + writeTrashFile(".gitattributes", "*.cat merge=union"); + writeTrashFile("main.cat", "A\n" + "B\n" + "C\n" + "D\n"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }, g -> { + try { + writeTrashFile("main.cat", "A\n" + "G\n" + "C\n" + "F\n"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }, g -> { + try { + writeTrashFile("main.cat", "A\n" + "E\n" + "C\n" + "D\n"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + })) { + // Check that the merge attribute is set to union + assertAddMergeAttributeCustom(REFS_HEADS_LEFT, "main.cat", "union"); + assertAddMergeAttributeCustom(REFS_HEADS_RIGHT, "main.cat", + "union"); + + checkoutBranch(REFS_HEADS_LEFT); + // Merge refs/heads/left -> refs/heads/right + + MergeResult mergeResult = git.merge() + .include(git.getRepository().resolve(REFS_HEADS_RIGHT)) + .call(); + assertEquals(MergeStatus.MERGED, mergeResult.getMergeStatus()); + + // Check that the file is the union of both branches (no conflict + // marker added) + String result = read(writeTrashFile("res.cat", + "A\n" + "G\n" + "E\n" + "C\n" + "F\n")); + assertEquals(result, read(git.getRepository().getWorkTree().toPath() + .resolve("main.cat").toFile())); + } + } + + @Test public void mergeBinaryFile_NoAttr_Conflict() throws IllegalStateException, IOException, NoHeadException, ConcurrentRefUpdateException, CheckoutConflictException, InvalidMergeHeadsException,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameGeneratorCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameGeneratorCacheTest.java new file mode 100644 index 0000000..65cac11 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameGeneratorCacheTest.java
@@ -0,0 +1,398 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * 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.blame; + +import static java.lang.String.join; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.jgit.blame.cache.BlameCache; +import org.eclipse.jgit.blame.cache.CacheRegion; +import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Test; + +public class BlameGeneratorCacheTest extends RepositoryTestCase { + private static final String FILE = "file.txt"; + + /** + * Simple history: + * + * <pre> + * C1 C2 C3 C4 C4 blame + * lines ---------------------------------- + * L1 | C1 C1 C1 C1 C1 + * L2 | C1 C1 *C3 *C4 C4 + * L3 | C1 C1 *C3 C3 C3 + * L4 | *C2 C2 *C4 C4 + * </pre> + * + * @throws Exception any error + */ + @Test + public void blame_simple_correctRegions() throws Exception { + RevCommit c1, c2, c3, c4; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = commit(r, lines("L1C1", "L2C1", "L3C1")); + c2 = commit(r, lines("L1C1", "L2C1", "L3C1", "L4C2"), c1); + c3 = commit(r, lines("L1C1", "L2C3", "L3C3", "L4C2"), c2); + c4 = commit(r, lines("L1C1", "L2C4", "L3C3", "L4C4"), c3); + } + + List<EmittedRegion> expectedRegions = Arrays.asList( + new EmittedRegion(c1, 0, 1), + new EmittedRegion(c4, 1, 2), + new EmittedRegion(c3, 2, 3), + new EmittedRegion(c4, 3, 4)); + + assertRegions(c4, null, expectedRegions, 4); + assertRegions(c4, emptyCache(), expectedRegions, 4); + assertRegions(c4, blameAndCache(c4), expectedRegions, 4); + assertRegions(c4, blameAndCache(c3), expectedRegions, 4); + assertRegions(c4, blameAndCache(c2), expectedRegions, 4); + assertRegions(c4, blameAndCache(c1), expectedRegions, 4); + } + + @Test + public void blame_simple_cacheUsage() throws Exception { + RevCommit c1, c2, c3, c4; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = commit(r, lines("L1C1", "L2C1", "L3C1")); + c2 = commit(r, lines("L1C1", "L2C1", "L3C1", "L4C2"), c1); + c3 = commit(r, lines("L1C1", "L2C3", "L3C3", "L4C2"), c2); + c4 = commit(r, lines("L1C1", "L2C4", "L3C3", "L4C4"), c3); + } + + assertCacheUsage(c4, null, false, 4); + assertCacheUsage(c4, emptyCache(), false, 4); + assertCacheUsage(c4, blameAndCache(c4), true, 1); + assertCacheUsage(c4, blameAndCache(c3), true, 2); + assertCacheUsage(c4, blameAndCache(c2), true, 3); + assertCacheUsage(c4, blameAndCache(c1), true, 4); + } + + /** + * Overwrite: + * + * <pre> + * C1 C2 C3 C3 blame + * lines ---------------------------------- + * L1 | C1 C1 *C3 C3 + * L2 | C1 C1 *C3 C3 + * L3 | C1 C1 *C3 C3 + * L4 | *C2 + * </pre> + * + * @throws Exception any error + */ + @Test + public void blame_ovewrite_correctRegions() throws Exception { + RevCommit c1, c2, c3; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = commit(r, lines("L1C1", "L2C1", "L3C1")); + c2 = commit(r, lines("L1C1", "L2C1", "L3C1", "L4C2"), c1); + c3 = commit(r, lines("L1C3", "L2C3", "L3C3"), c2); + } + + List<EmittedRegion> expectedRegions = Arrays.asList( + new EmittedRegion(c3, 0, 3)); + + assertRegions(c3, null, expectedRegions, 3); + assertRegions(c3, emptyCache(), expectedRegions, 3); + assertRegions(c3, blameAndCache(c3), expectedRegions, 3); + assertRegions(c3, blameAndCache(c2), expectedRegions, 3); + assertRegions(c3, blameAndCache(c1), expectedRegions, 3); + } + + @Test + public void blame_overwrite_cacheUsage() throws Exception { + RevCommit c1, c2, c3; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = commit(r, lines("L1C1", "L2C1", "L3C1")); + c2 = commit(r, lines("L1C1", "L2C1", "L3C1", "L4C2"), c1); + c3 = commit(r, lines("L1C3", "L2C3", "L3C3"), c2); + } + + assertCacheUsage(c3, null, false, 1); + assertCacheUsage(c3, emptyCache(), false, 1); + assertCacheUsage(c3, blameAndCache(c3), true, 1); + assertCacheUsage(c3, blameAndCache(c2), false, 1); + assertCacheUsage(c3, blameAndCache(c1), false, 1); + } + + /** + * Merge: + * + * <pre> + * root + * ---- + * L1 - + * L2 - + * L3 - + * / \ + * sideA sideB + * ----- ----- + * *L1 a L1 - + * *L2 a L2 - + * *L3 a L3 - + * *L4 a *L4 b + * L5 - *L5 b + * L6 - *L6 b + * L7 - *L7 b + * \ / + * merge + * ----- + * L1-L4 a (from sideA) + * L5-L7 - (common, from root) + * L8-L11 b (from sideB) + * </pre> + * + * @throws Exception any error + */ + @Test + public void blame_merge_correctRegions() throws Exception { + RevCommit root, sideA, sideB, mergedTip; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + root = commitAsLines(r, "---"); + sideA = commitAsLines(r, "aaaa---", root); + sideB = commitAsLines(r, "---bbbb", root); + mergedTip = commitAsLines(r, "aaaa---bbbb", sideA, sideB); + } + + List<EmittedRegion> expectedRegions = Arrays.asList( + new EmittedRegion(sideA, 0, 4), + new EmittedRegion(root, 4, 7), + new EmittedRegion(sideB, 7, 11)); + + assertRegions(mergedTip, null, expectedRegions, 11); + assertRegions(mergedTip, emptyCache(), expectedRegions, 11); + assertRegions(mergedTip, blameAndCache(root), expectedRegions, 11); + assertRegions(mergedTip, blameAndCache(sideA), expectedRegions, 11); + assertRegions(mergedTip, blameAndCache(sideB), expectedRegions, 11); + assertRegions(mergedTip, blameAndCache(mergedTip), expectedRegions, 11); + } + + @Test + public void blame_merge_cacheUsage() throws Exception { + RevCommit root, sideA, sideB, mergedTip; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + root = commitAsLines(r, "---"); + sideA = commitAsLines(r, "aaaa---", root); + sideB = commitAsLines(r, "---bbbb", root); + mergedTip = commitAsLines(r, "aaaa---bbbb", sideA, sideB); + } + + assertCacheUsage(mergedTip, null, /* cacheUsed */ false, + /* candidates */ 4); + assertCacheUsage(mergedTip, emptyCache(), false, 4); + assertCacheUsage(mergedTip, blameAndCache(mergedTip), true, 1); + + // While splitting unblamed regions to parents, sideA comes first + // and gets "aaaa----". Processing is by commit time, so sideB is + // explored first + assertCacheUsage(mergedTip, blameAndCache(sideA), true, 3); + assertCacheUsage(mergedTip, blameAndCache(sideB), true, 4); + assertCacheUsage(mergedTip, blameAndCache(root), true, 4); + } + + /** + * Moving block (insertion) + * + * <pre> + * C1 C2 C3 C3 blame + * lines ---------------------------------- + * L1 | C1 C1 C1 C1 + * L2 | C1 *C2 C2 C2 + * L3 | C1 *C3 C3 + * L4 | C1 C1 + * </pre> + * + * @throws Exception any error + */ + @Test + public void blame_movingBlock_correctRegions() throws Exception { + RevCommit c1, c2, c3; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = commit(r, lines("L1C1", "L2C1")); + c2 = commit(r, lines("L1C1", "middle", "L2C1"), c1); + c3 = commit(r, lines("L1C1", "middle", "extra", "L2C1"), c2); + } + + List<EmittedRegion> expectedRegions = Arrays.asList( + new EmittedRegion(c1, 0, 1), + new EmittedRegion(c2, 1, 2), + new EmittedRegion(c3, 2, 3), + new EmittedRegion(c1, 3, 4)); + + assertRegions(c3, null, expectedRegions, 4); + assertRegions(c3, emptyCache(), expectedRegions, 4); + assertRegions(c3, blameAndCache(c3), expectedRegions, 4); + assertRegions(c3, blameAndCache(c2), expectedRegions, 4); + assertRegions(c3, blameAndCache(c1), expectedRegions, 4); + } + + @Test + public void blame_movingBlock_cacheUsage() throws Exception { + RevCommit c1, c2, c3; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = commitAsLines(r, "root---"); + c2 = commitAsLines(r, "rootXXX---", c1); + c3 = commitAsLines(r, "rootYYYXXX---", c2); + } + + assertCacheUsage(c3, null, false, 3); + assertCacheUsage(c3, emptyCache(), false, 3); + assertCacheUsage(c3, blameAndCache(c3), true, 1); + assertCacheUsage(c3, blameAndCache(c2), true, 2); + assertCacheUsage(c3, blameAndCache(c1), true, 3); + } + + private void assertRegions(RevCommit commit, InMemoryBlameCache cache, + List<EmittedRegion> expectedRegions, int resultLineCount) + throws IOException { + try (BlameGenerator gen = new BlameGenerator(db, FILE, cache)) { + gen.push(null, db.parseCommit(commit)); + List<EmittedRegion> regions = consume(gen); + assertRegionsEquals(expectedRegions, regions); + assertAllLinesCovered(/* lines= */ resultLineCount, regions); + } + } + + private void assertCacheUsage(RevCommit commit, InMemoryBlameCache cache, + boolean useCache, int candidatesVisited) throws IOException { + try (BlameGenerator gen = new BlameGenerator(db, FILE, cache)) { + gen.push(null, db.parseCommit(commit)); + consume(gen); + assertEquals(useCache, gen.getStats().isCacheHit()); + assertEquals(candidatesVisited, + gen.getStats().getCandidatesVisited()); + } + } + + private static void assertAllLinesCovered(int lines, + List<EmittedRegion> regions) { + Collections.sort(regions); + assertEquals("Starts in first line", 0, regions.get(0).resultStart()); + for (int i = 1; i < regions.size(); i++) { + assertEquals("No gaps", regions.get(i).resultStart(), + regions.get(i - 1).resultEnd()); + } + assertEquals("Ends in last line", lines, + regions.get(regions.size() - 1).resultEnd()); + } + + private static void assertRegionsEquals( + List<EmittedRegion> expected, List<EmittedRegion> actual) { + assertEquals(expected.size(), actual.size()); + Collections.sort(actual); + for (int i = 0; i < expected.size(); i++) { + assertEquals(String.format("List differ in element %d", i), + expected.get(i), actual.get(i)); + } + } + + private static InMemoryBlameCache emptyCache() { + return new InMemoryBlameCache("<empty>"); + } + + private List<EmittedRegion> consume(BlameGenerator generator) + throws IOException { + List<EmittedRegion> result = new ArrayList<>(); + while (generator.next()) { + EmittedRegion genRegion = new EmittedRegion( + generator.getSourceCommit().toObjectId(), + generator.getResultStart(), generator.getResultEnd()); + result.add(genRegion); + } + return result; + } + + private InMemoryBlameCache blameAndCache(RevCommit commit) + throws IOException { + List<CacheRegion> regions; + try (BlameGenerator generator = new BlameGenerator(db, FILE)) { + generator.push(null, commit); + regions = consume(generator).stream() + .map(EmittedRegion::asCacheRegion) + .collect(Collectors.toUnmodifiableList()); + } + InMemoryBlameCache cache = new InMemoryBlameCache("<x>"); + cache.put(commit, FILE, regions); + return cache; + } + + private static RevCommit commitAsLines(TestRepository<?> r, + String charPerLine, RevCommit... parents) throws Exception { + return commit(r, charPerLine.replaceAll("\\S", "$0\n"), parents); + } + + private static RevCommit commit(TestRepository<?> r, String contents, + RevCommit... parents) throws Exception { + return r.commit(r.tree(r.file(FILE, r.blob(contents))), parents); + } + + private static String lines(String... l) { + return join("\n", l); + } + + private record EmittedRegion(ObjectId oid, int resultStart, int resultEnd) + implements Comparable<EmittedRegion> { + @Override + public int compareTo(EmittedRegion o) { + return resultStart - o.resultStart; + } + + CacheRegion asCacheRegion() { + return new CacheRegion(FILE, oid, resultStart, resultEnd); + } + } + + private static class InMemoryBlameCache implements BlameCache { + + private final Map<Key, List<CacheRegion>> cache = new HashMap<>(); + + private final String description; + + public InMemoryBlameCache(String description) { + this.description = description; + } + + @Override + public List<CacheRegion> get(Repository repo, ObjectId commitId, + String path) throws IOException { + return cache.get(new Key(commitId.name(), path)); + } + + public void put(ObjectId commitId, String path, + List<CacheRegion> cachedRegions) { + cache.put(new Key(commitId.name(), path), cachedRegions); + } + + @Override + public String toString() { + return "InMemoryCache: " + description; + } + + record Key(String commitId, String path) { + } + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameRegionMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameRegionMergerTest.java new file mode 100644 index 0000000..1b28676 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameRegionMergerTest.java
@@ -0,0 +1,320 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * 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.blame; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.eclipse.jgit.blame.cache.CacheRegion; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Test; + +public class BlameRegionMergerTest extends RepositoryTestCase { + + private static final ObjectId O1 = ObjectId + .fromString("ff6dd8db6edc9aa0ac58fea1d14a55be46c3eb14"); + + private static final ObjectId O2 = ObjectId + .fromString("c3c7f680c6bee238617f25f6aa85d0b565fc8ecb"); + + private static final ObjectId O3 = ObjectId + .fromString("29e014aad0399fe8ede7c101d01b6e440ac9966b"); + + List<RevCommit> fakeCommits = List.of(new FakeRevCommit(O1), + new FakeRevCommit(O2), new FakeRevCommit(O3)); + + // In reverse order, so the code doesn't assume a sorted list + List<CacheRegion> cachedRegions = List.of( + new CacheRegion("README", O3, 20, 30), + new CacheRegion("README", O2, 10, 20), + new CacheRegion("README", O1, 0, 10)); + + BlameRegionMerger blamer = new BlameRegionMergerFakeCommits(fakeCommits, + cachedRegions); + + @Test + public void intersectRegions_allInside() { + Region unblamed = new Region(15, 18, 10); + CacheRegion blamed = new CacheRegion("README", O1, 10, 90); + + Region result = BlameRegionMerger.intersectRegions(unblamed, blamed); + // Same lines in result and source + assertEquals(15, result.resultStart); + assertEquals(18, result.sourceStart); + assertEquals(10, result.length); + assertNull(result.next); + } + + @Test + public void intersectRegions_startsBefore() { + // Intesecting [4, 14) with [10, 90) + Region unblamed = new Region(30, 4, 10); + CacheRegion blamed = new CacheRegion("README", O1, 10, 90); + + Region result = BlameRegionMerger.intersectRegions(unblamed, blamed); + + // The unblamed region starting at 4 (sourceStart), starts at 30 in the + // original file (resultStart). e.g. some commit introduced + // lines. If we take the second portion of the region, we need to move + // the result start accordingly. + assertEquals(36, result.resultStart); + assertEquals(10, result.sourceStart); + assertEquals(4, result.length); + assertNull(result.next); + } + + @Test + public void intersectRegions_endsAfter() { + // Intesecting [85, 95) with [10, 90) + Region unblamed = new Region(30, 85, 10); + CacheRegion blamed = new CacheRegion("README", O1, 10, 90); + + Region result = BlameRegionMerger.intersectRegions(unblamed, blamed); + + assertEquals(30, result.resultStart); + assertEquals(85, result.sourceStart); + assertEquals(5, result.length); + assertNull(result.next); + } + + @Test + public void intersectRegions_spillOverBothSides() { + // Intesecting [5, 100) with [10, 90) + Region unblamed = new Region(30, 5, 95); + CacheRegion blamed = new CacheRegion("README", O1, 10, 90); + + Region result = BlameRegionMerger.intersectRegions(unblamed, blamed); + + assertEquals(35, result.resultStart); + assertEquals(10, result.sourceStart); + assertEquals(80, result.length); + assertNull(result.next); + } + + @Test + public void intersectRegions_exactMatch() { + // Intesecting [5, 100) with [10, 90) + Region unblamed = new Region(30, 10, 80); + CacheRegion blamed = new CacheRegion("README", O1, 10, 90); + + Region result = BlameRegionMerger.intersectRegions(unblamed, blamed); + + assertEquals(30, result.resultStart); + assertEquals(10, result.sourceStart); + assertEquals(80, result.length); + assertNull(result.next); + } + + @Test + public void findOverlaps_allInside() { + Region unblamed = new Region(0, 11, 4); + List<CacheRegion> overlaps = blamer.findOverlaps(unblamed); + assertEquals(1, overlaps.size()); + assertEquals(10, overlaps.get(0).getStart()); + assertEquals(20, overlaps.get(0).getEnd()); + } + + @Test + public void findOverlaps_overTwoRegions() { + Region unblamed = new Region(0, 8, 4); + List<CacheRegion> overlaps = blamer.findOverlaps(unblamed); + assertEquals(2, overlaps.size()); + assertEquals(0, overlaps.get(0).getStart()); + assertEquals(10, overlaps.get(0).getEnd()); + assertEquals(10, overlaps.get(1).getStart()); + assertEquals(20, overlaps.get(1).getEnd()); + } + + @Test + public void findOverlaps_overThreeRegions() { + Region unblamed = new Region(0, 8, 15); + List<CacheRegion> overlaps = blamer.findOverlaps(unblamed); + assertEquals(3, overlaps.size()); + assertEquals(0, overlaps.get(0).getStart()); + assertEquals(10, overlaps.get(0).getEnd()); + assertEquals(10, overlaps.get(1).getStart()); + assertEquals(20, overlaps.get(1).getEnd()); + assertEquals(20, overlaps.get(2).getStart()); + assertEquals(30, overlaps.get(2).getEnd()); + } + + @Test + public void blame_exactOverlap() throws IOException { + Region unblamed = new Region(0, 10, 10); + List<Candidate> blamed = blamer.mergeOneRegion(unblamed); + + assertEquals(1, blamed.size()); + Candidate c = blamed.get(0); + assertEquals(c.sourceCommit.name(), O2.name()); + assertEquals(c.regionList.resultStart, unblamed.resultStart); + assertEquals(c.regionList.sourceStart, unblamed.sourceStart); + assertEquals(10, c.regionList.length); + assertNull(c.regionList.next); + } + + @Test + public void blame_corruptedIndex() { + Region outOfRange = new Region(0, 43, 4); + // This region is out of the blamed area + assertThrows(IOException.class, + () -> blamer.mergeOneRegion(outOfRange)); + } + + @Test + public void blame_allInsideOneBlamedRegion() throws IOException { + Region unblamed = new Region(0, 5, 3); + // This region if fully blamed to O1 + List<Candidate> blamed = blamer.mergeOneRegion(unblamed); + assertEquals(1, blamed.size()); + Candidate c = blamed.get(0); + assertEquals(c.sourceCommit.name(), O1.name()); + assertEquals(c.regionList.resultStart, unblamed.resultStart); + assertEquals(c.regionList.sourceStart, unblamed.sourceStart); + assertEquals(3, c.regionList.length); + assertNull(c.regionList.next); + } + + @Test + public void blame_overTwoBlamedRegions() throws IOException { + Region unblamed = new Region(0, 8, 5); + // (8, 10) belongs go C1, (10, 13) to C2 + List<Candidate> blamed = blamer.mergeOneRegion(unblamed); + assertEquals(2, blamed.size()); + Candidate c = blamed.get(0); + assertEquals(c.sourceCommit.name(), O1.name()); + assertEquals(unblamed.resultStart, c.regionList.resultStart); + assertEquals(unblamed.sourceStart, c.regionList.sourceStart); + assertEquals(2, c.regionList.length); + assertNull(c.regionList.next); + + c = blamed.get(1); + assertEquals(c.sourceCommit.name(), O2.name()); + assertEquals(2, c.regionList.resultStart); + assertEquals(10, c.regionList.sourceStart); + assertEquals(3, c.regionList.length); + assertNull(c.regionList.next); + } + + @Test + public void blame_all() throws IOException { + Region unblamed = new Region(0, 0, 30); + List<Candidate> blamed = blamer.mergeOneRegion(unblamed); + assertEquals(3, blamed.size()); + Candidate c = blamed.get(0); + assertEquals(c.sourceCommit.name(), O1.name()); + assertEquals(unblamed.resultStart, c.regionList.resultStart); + assertEquals(unblamed.sourceStart, c.regionList.sourceStart); + assertEquals(10, c.regionList.length); + assertNull(c.regionList.next); + + c = blamed.get(1); + assertEquals(c.sourceCommit.name(), O2.name()); + assertEquals(10, c.regionList.resultStart); + assertEquals(10, c.regionList.sourceStart); + assertEquals(10, c.regionList.length); + assertNull(c.regionList.next); + + c = blamed.get(2); + assertEquals(c.sourceCommit.name(), O3.name()); + assertEquals(20, c.regionList.resultStart); + assertEquals(20, c.regionList.sourceStart); + assertEquals(10, c.regionList.length); + assertNull(c.regionList.next); + } + + @Test + public void blame_fromCandidate() { + // We don't use anything from the candidate besides the + // regionList + Candidate c = new Candidate(null, null, null); + c.regionList = new Region(0, 8, 5); + c.regionList.next = new Region(22, 22, 4); + + Candidate blamed = blamer.mergeCandidate(c); + // Three candidates + assertNotNull(blamed); + assertNotNull(blamed.queueNext); + assertNotNull(blamed.queueNext.queueNext); + assertNull(blamed.queueNext.queueNext.queueNext); + + assertEquals(O1.name(), blamed.sourceCommit.name()); + + Candidate second = blamed.queueNext; + assertEquals(O2.name(), second.sourceCommit.name()); + + Candidate third = blamed.queueNext.queueNext; + assertEquals(O3.name(), third.sourceCommit.name()); + } + + @Test + public void blame_fromCandidate_twiceCandidateInOutput() { + Candidate c = new Candidate(null, null, null); + // This produces O1 and O2 + c.regionList = new Region(0, 8, 5); + // This produces O2 and O3 + c.regionList.next = new Region(20, 15, 7); + + Candidate blamed = blamer.mergeCandidate(c); + assertCandidateSingleRegion(O1, 2, blamed); + blamed = blamed.queueNext; + assertCandidateSingleRegion(O2, 3, blamed); + // We do not merge candidates afterwards, so these are + // two different candidates to the same source + blamed = blamed.queueNext; + assertCandidateSingleRegion(O2, 5, blamed); + blamed = blamed.queueNext; + assertCandidateSingleRegion(O3, 2, blamed); + assertNull(blamed.queueNext); + } + + private static void assertCandidateSingleRegion(ObjectId expectedOid, + int expectedLength, Candidate actual) { + assertNotNull("candidate", actual); + assertNotNull("region list not empty", actual.regionList); + assertNull("region list has only one element", actual.regionList.next); + assertEquals(expectedOid, actual.sourceCommit); + assertEquals(expectedLength, actual.regionList.length); + } + + private static final class BlameRegionMergerFakeCommits + extends BlameRegionMerger { + + private final Map<ObjectId, RevCommit> cache; + + BlameRegionMergerFakeCommits(List<RevCommit> commits, + List<CacheRegion> blamedRegions) { + super(null, null, blamedRegions); + cache = commits.stream().collect(Collectors + .toMap(RevCommit::toObjectId, Function.identity())); + } + + @Override + protected RevCommit parse(ObjectId oid) { + return cache.get(oid); + } + } + + private static final class FakeRevCommit extends RevCommit { + FakeRevCommit(AnyObjectId id) { + super(id); + } + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java new file mode 100644 index 0000000..1352871 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java
@@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License 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.diff; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.stream.Collectors; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.junit.Test; + +public class DiffFormatterBuiltInDriverTest extends RepositoryTestCase { + @Test + public void testCppDriver() throws Exception { + String fileName = "greeting.c"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.c diff=cpp"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings") + .replace("baz", "qux")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = + "@@ -27,7 +27,7 @@ void getPersonalizedGreeting(char *result, const char *name, const char *timeOfD\n" + + "@@ -37,7 +37,7 @@ int main() {"; + assertEquals(expected, actual); + } + } + + @Test + public void testDtsDriver() throws Exception { + String fileName = "sample.dtsi"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.dtsi diff=dts"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("clock-frequency = <24000000>", + "clock-frequency = <48000000>")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = "@@ -20,6 +20,6 @@ uart0: uart@101f1000 {"; + assertEquals(expected, actual); + } + } + + @Test + public void testJavaDriver() throws Exception { + String resourceName = "greeting.javasource"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(resourceName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.java diff=java"); + String fileName = "Greeting.java"; + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings") + .replace("baz", "qux")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = + "@@ -22,7 +22,7 @@ public String getPersonalizedGreeting(String name, String timeOfDay) {\n" + + "@@ -32,6 +32,6 @@ public static void main(String[] args) {"; + assertEquals(expected, actual); + } + } + + @Test + public void testPythonDriver() throws Exception { + String fileName = "greeting.py"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.py diff=python"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = "@@ -16,7 +16,7 @@ def get_personalized_greeting(self, name, time_of_day):"; + assertEquals(expected, actual); + } + } + + @Test + public void testRustDriver() throws Exception { + String fileName = "greeting.rs"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.rs diff=rust"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings") + .replace("baz", "qux")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = + "@@ -14,7 +14,7 @@ fn get_personalized_greeting(&self, name: &str, time_of_day: &str) -> String {\n" + + "@@ -23,5 +23,5 @@ fn main() {"; + assertEquals(expected, actual); + } + } + + private String getHunkHeaders(RevCommit c1, RevCommit c2, + ByteArrayOutputStream os, DiffFormatter diffFormatter) + throws IOException { + diffFormatter.setRepository(db); + diffFormatter.format(new CanonicalTreeParser(null, db.newObjectReader(), + c1.getTree()), + new CanonicalTreeParser(null, db.newObjectReader(), + c2.getTree())); + diffFormatter.flush(); + return Arrays.stream(os.toString(StandardCharsets.UTF_8).split("\n")) + .filter(line -> line.startsWith("@@")) + .collect(Collectors.joining("\n")); + } + + private RevCommit createCommit(Git git, String fileName, String body) + throws IOException, GitAPIException { + writeTrashFile(fileName, body); + git.add().addFilepattern(".").call(); + return git.commit().setMessage("message").call(); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java index c3b9387..5065b57 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/BareSuperprojectWriterTest.java
@@ -12,6 +12,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -22,6 +23,7 @@ import org.eclipse.jgit.gitrepo.BareSuperprojectWriter.BareWriterConfig; import org.eclipse.jgit.gitrepo.RepoCommand.RemoteReader; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; @@ -68,6 +70,49 @@ public void write_setGitModulesContents() throws Exception { } @Test + public void write_setGitModulesContents_pinned() throws Exception { + try (Repository bareRepo = createBareRepository()) { + RepoProject pinWithUpstream = new RepoProject("pinWithUpstream", + "path/x", "cbc0fae7e1911d27e1de37d364698dba4411c78b", + "remote", ""); + pinWithUpstream.setUrl("http://example.com/a"); + pinWithUpstream.setUpstream("branchX"); + + RepoProject pinWithoutUpstream = new RepoProject( + "pinWithoutUpstream", "path/y", + "cbc0fae7e1911d27e1de37d364698dba4411c78b", "remote", ""); + pinWithoutUpstream.setUrl("http://example.com/b"); + + RemoteReader mockRemoteReader = mock(RemoteReader.class); + + BareSuperprojectWriter w = new BareSuperprojectWriter(bareRepo, + null, "refs/heads/master", author, mockRemoteReader, + BareWriterConfig.getDefault(), List.of()); + + RevCommit commit = w + .write(Arrays.asList(pinWithUpstream, pinWithoutUpstream)); + + String contents = readContents(bareRepo, commit, ".gitmodules"); + Config cfg = new Config(); + cfg.fromText(contents); + + assertThat(cfg.getString("submodule", "pinWithUpstream", "path"), + is("path/x")); + assertThat(cfg.getString("submodule", "pinWithUpstream", "url"), + is("http://example.com/a")); + assertThat(cfg.getString("submodule", "pinWithUpstream", "ref"), + is("branchX")); + + assertThat(cfg.getString("submodule", "pinWithoutUpstream", "path"), + is("path/y")); + assertThat(cfg.getString("submodule", "pinWithoutUpstream", "url"), + is("http://example.com/b")); + assertThat(cfg.getString("submodule", "pinWithoutUpstream", "ref"), + nullValue()); + } + } + + @Test public void write_setExtraContents() throws Exception { try (Repository bareRepo = createBareRepository()) { RepoProject repoProject = new RepoProject("subprojectX", "path/to",
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java index 20958a8..fca27d3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
@@ -11,6 +11,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -18,7 +19,9 @@ import java.io.IOException; import java.net.URI; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -138,6 +141,72 @@ public void testRemoveProject() throws Exception { .collect(Collectors.toSet())); } + @Test + public void testPinProjectWithUpstream() throws Exception { + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"pin-with-upstream\"") + .append(" revision=\"9b2fe85c0279f4d5ac69f07ddcd48566c3555405\"") + .append(" upstream=\"branchX\"/>") + .append("<project path=\"bar\" name=\"pin-without-upstream\"") + .append(" revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />") + .append("</manifest>"); + + ManifestParser parser = new ManifestParser(null, null, "master", + "https://git.google.com/", null, null); + parser.read(new ByteArrayInputStream( + xmlContent.toString().getBytes(UTF_8))); + + Map<String, RepoProject> repos = parser.getProjects().stream().collect( + Collectors.toMap(RepoProject::getName, Function.identity())); + assertEquals(2, repos.size()); + + RepoProject foo = repos.get("pin-with-upstream"); + assertEquals("pin-with-upstream", foo.getName()); + assertEquals("9b2fe85c0279f4d5ac69f07ddcd48566c3555405", + foo.getRevision()); + assertEquals("branchX", foo.getUpstream()); + + RepoProject bar = repos.get("pin-without-upstream"); + assertEquals("pin-without-upstream", bar.getName()); + assertEquals("76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0", + bar.getRevision()); + assertNull(bar.getUpstream()); + } + + @Test + public void testWithDestBranch() throws Exception { + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"foo\"") + .append(" dest-branch=\"branchX\"/>") + .append("<project path=\"bar\" name=\"bar\"/>") + .append("</manifest>"); + + ManifestParser parser = new ManifestParser(null, null, "master", + "https://git.google.com/", null, null); + parser.read(new ByteArrayInputStream( + xmlContent.toString().getBytes(UTF_8))); + + Map<String, RepoProject> repos = parser.getProjects().stream().collect( + Collectors.toMap(RepoProject::getName, Function.identity())); + assertEquals(2, repos.size()); + + RepoProject foo = repos.get("foo"); + assertEquals("foo", foo.getName()); + assertEquals("branchX", foo.getDestBranch()); + + RepoProject bar = repos.get("bar"); + assertEquals("bar", bar.getName()); + assertNull(bar.getDestBranch()); + } + void testNormalize(String in, String want) { URI got = ManifestParser.normalizeEmptyPath(URI.create(in)); if (!got.toString().equals(want)) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index ca6f2e1..3162e79 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -1171,6 +1171,94 @@ public void testRecordRemoteBranch() throws Exception { } } + @Test + public void testRecordRemoteBranch_pinned() throws Exception { + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"pin-noupstream\"") + .append(" name=\"pin-noupstream\"") + .append(" revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />") + .append("<project path=\"pin-upstream\"") + .append(" name=\"pin-upstream\"") + .append(" upstream=\"branchX\"") + .append(" revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />") + .append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).setRecordRemoteBranch(true).call(); + // Clone it + File directory = createTempDirectory("testBareRepo"); + try (Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository();) { + // The .gitmodules file should exist + File gitmodules = new File(localDb.getWorkTree(), ".gitmodules"); + assertTrue("The .gitmodules file should exist", + gitmodules.exists()); + FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED); + c.load(); + assertEquals("Pinned submodule with upstream records the ref", + "branchX", c.getString("submodule", "pin-upstream", "ref")); + assertNull("Pinned submodule without upstream don't have ref", + c.getString("submodule", "pin-noupstream", "ref")); + } + } + + @Test + public void testRecordRemoteBranch_pinned_nameConflict() throws Exception { + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"pin-upstream\"") + .append(" name=\"pin-upstream\"") + .append(" upstream=\"branchX\"") + .append(" revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />") + .append("<project path=\"pin-upstream-name-conflict\"") + .append(" name=\"pin-upstream\"") + .append(" upstream=\"branchX\"") + .append(" revision=\"76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0\" />") + .append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).setRecordRemoteBranch(true).call(); + // Clone it + File directory = createTempDirectory("testBareRepo"); + try (Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository();) { + // The .gitmodules file should exist + File gitmodules = new File(localDb.getWorkTree(), ".gitmodules"); + assertTrue("The .gitmodules file should exist", + gitmodules.exists()); + FileBasedConfig c = new FileBasedConfig(gitmodules, FS.DETECTED); + c.load(); + assertEquals("Upstream is preserved in name conflict", "branchX", + c.getString("submodule", "pin-upstream/pin-upstream", + "ref")); + assertEquals("Upstream is preserved in name conflict (other side)", + "branchX", c.getString("submodule", + "pin-upstream/pin-upstream-name-conflict", "ref")); + } + } @Test public void testRecordSubmoduleLabels() throws Exception {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriterTest.java index 9f65ee2..80a0f0c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriterTest.java
@@ -10,6 +10,7 @@ package org.eclipse.jgit.internal.storage.commitgraph; +import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.Assert.assertArrayEquals; @@ -19,8 +20,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashSet; +import java.util.List; +import java.util.Optional; import java.util.Set; import org.eclipse.jgit.dircache.DirCacheEntry; @@ -413,6 +418,27 @@ public void testReuseBloomFilters() throws Exception { "119,69,63,-8,0,")); } + @Test + public void testPathDiffCalculator_skipUnchangedTree() throws Exception { + RevCommit root = tr.commit(tr.tree( + tr.file("d/sd1/f1", tr.blob("f1")), + tr.file("d/sd2/f2", tr.blob("f2")))); + RevCommit tip = tr.commit(tr.tree( + tr.file("d/sd1/f1", tr.blob("f1")), + tr.file("d/sd2/f2", tr.blob("f2B"))), root); + CommitGraphWriter.PathDiffCalculator c = new CommitGraphWriter.PathDiffCalculator(); + + Optional<HashSet<ByteBuffer>> byteBuffers = c.changedPaths(walk.getObjectReader(), tip); + + assertTrue(byteBuffers.isPresent()); + List<String> asString = byteBuffers.get().stream() + .map(b -> StandardCharsets.UTF_8.decode(b).toString()) + .collect(toList()); + assertThat(asString, containsInAnyOrder("d", "d/sd2", "d/sd2/f2")); + // We don't walk into d/sd1/f1 + assertEquals(1, c.stepCounter); + } + RevCommit commit(RevCommit... parents) throws Exception { return tr.commit(parents); }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java new file mode 100644 index 0000000..2c4b432 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java
@@ -0,0 +1,210 @@ +/* + * Copyright (c) 2024, 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.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertArrayEquals; + +import java.util.List; + +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.junit.Test; + +public class AggregatedBlockCacheStatsTest { + @Test + public void getName() { + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of()); + + assertThat(aggregatedBlockCacheStats.getName(), + equalTo(AggregatedBlockCacheStats.class.getName())); + } + + @Test + public void getCurrentSize_aggregatesCurrentSizes() { + long[] currentSizes = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + packStats.addToLiveBytes(new TestKey(PackExt.PACK), 5); + currentSizes[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + bitmapStats.addToLiveBytes(new TestKey(PackExt.BITMAP_INDEX), 6); + currentSizes[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + indexStats.addToLiveBytes(new TestKey(PackExt.INDEX), 7); + currentSizes[PackExt.INDEX.getPosition()] = 7; + + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); + + assertArrayEquals(aggregatedBlockCacheStats.getCurrentSize(), + currentSizes); + } + + @Test + public void getHitCount_aggregatesHitCounts() { + long[] hitCounts = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementHit(new TestKey(PackExt.PACK))); + hitCounts[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> bitmapStats + .incrementHit(new TestKey(PackExt.BITMAP_INDEX))); + hitCounts[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementHit(new TestKey(PackExt.INDEX))); + hitCounts[PackExt.INDEX.getPosition()] = 7; + + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); + + assertArrayEquals(aggregatedBlockCacheStats.getHitCount(), hitCounts); + } + + @Test + public void getMissCount_aggregatesMissCounts() { + long[] missCounts = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementMiss(new TestKey(PackExt.PACK))); + missCounts[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> bitmapStats + .incrementMiss(new TestKey(PackExt.BITMAP_INDEX))); + missCounts[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementMiss(new TestKey(PackExt.INDEX))); + missCounts[PackExt.INDEX.getPosition()] = 7; + + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); + + assertArrayEquals(aggregatedBlockCacheStats.getMissCount(), missCounts); + } + + @Test + public void getTotalRequestCount_aggregatesRequestCounts() { + long[] totalRequestCounts = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, () -> { + packStats.incrementHit(new TestKey(PackExt.PACK)); + packStats.incrementMiss(new TestKey(PackExt.PACK)); + }); + totalRequestCounts[PackExt.PACK.getPosition()] = 10; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> { + bitmapStats.incrementHit(new TestKey(PackExt.BITMAP_INDEX)); + bitmapStats.incrementMiss(new TestKey(PackExt.BITMAP_INDEX)); + }); + totalRequestCounts[PackExt.BITMAP_INDEX.getPosition()] = 12; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, () -> { + indexStats.incrementHit(new TestKey(PackExt.INDEX)); + indexStats.incrementMiss(new TestKey(PackExt.INDEX)); + }); + totalRequestCounts[PackExt.INDEX.getPosition()] = 14; + + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); + + assertArrayEquals(aggregatedBlockCacheStats.getTotalRequestCount(), + totalRequestCounts); + } + + @Test + public void getHitRatio_aggregatesHitRatios() { + long[] hitRatios = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementHit(new TestKey(PackExt.PACK))); + hitRatios[PackExt.PACK.getPosition()] = 100; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> { + bitmapStats.incrementHit(new TestKey(PackExt.BITMAP_INDEX)); + bitmapStats.incrementMiss(new TestKey(PackExt.BITMAP_INDEX)); + }); + hitRatios[PackExt.BITMAP_INDEX.getPosition()] = 50; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementMiss(new TestKey(PackExt.INDEX))); + hitRatios[PackExt.INDEX.getPosition()] = 0; + + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); + + assertArrayEquals(aggregatedBlockCacheStats.getHitRatio(), hitRatios); + } + + @Test + public void getEvictions_aggregatesEvictions() { + long[] evictions = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementEvict(new TestKey(PackExt.PACK))); + evictions[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> bitmapStats + .incrementEvict(new TestKey(PackExt.BITMAP_INDEX))); + evictions[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementEvict(new TestKey(PackExt.INDEX))); + evictions[PackExt.INDEX.getPosition()] = 7; + + BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); + + assertArrayEquals(aggregatedBlockCacheStats.getEvictions(), evictions); + } + + private static void incrementCounter(int amount, Runnable fn) { + for (int i = 0; i < amount; i++) { + fn.run(); + } + } + + private static long[] createEmptyStatsArray() { + return new long[PackExt.values().length]; + } + + private static class TestKey extends DfsStreamKey { + TestKey(PackExt packExt) { + super(0, packExt); + } + + @Override + public boolean equals(Object o) { + return false; + } + } +} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java new file mode 100644 index 0000000..2e2f86b --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java
@@ -0,0 +1,67 @@ +package org.eclipse.jgit.internal.storage.dfs; + +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DEFAULT_NAME; +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.isA; + +import java.util.List; + +import org.junit.Test; + +public class ClockBlockCacheTableTest { + private static final String NAME = "name"; + + @Test + public void getName_nameNotConfigured_returnsDefaultName() { + ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( + createBlockCacheConfig()); + + assertThat(cacheTable.getName(), equalTo(DEFAULT_NAME)); + } + + @Test + public void getName_nameConfigured_returnsConfiguredName() { + ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( + createBlockCacheConfig().setName(NAME)); + + assertThat(cacheTable.getName(), equalTo(NAME)); + } + + @Test + public void getBlockCacheStats_nameNotConfigured_returnsBlockCacheStatsWithDefaultName() { + ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( + createBlockCacheConfig()); + + assertThat(cacheTable.getBlockCacheStats(), hasSize(1)); + assertThat(cacheTable.getBlockCacheStats().get(0).getName(), + equalTo(DEFAULT_NAME)); + } + + @Test + public void getBlockCacheStats_nameConfigured_returnsBlockCacheStatsWithConfiguredName() { + ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( + createBlockCacheConfig().setName(NAME)); + + assertThat(cacheTable.getBlockCacheStats(), hasSize(1)); + assertThat(cacheTable.getBlockCacheStats().get(0).getName(), + equalTo(NAME)); + } + + @Test + public void getAllBlockCacheStats() { + ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( + createBlockCacheConfig()); + + List<BlockCacheStats> blockCacheStats = cacheTable.getBlockCacheStats(); + assertThat(blockCacheStats, contains(isA(BlockCacheStats.class))); + } + + private static DfsBlockCacheConfig createBlockCacheConfig() { + return new DfsBlockCacheConfig().setBlockSize(512) + .setConcurrencyLevel(4).setBlockLimit(1024); + } +} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java index 2df0ba1..afa3179 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java
@@ -38,13 +38,37 @@ package org.eclipse.jgit.internal.storage.dfs; +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DEFAULT_NAME; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_CACHE_PREFIX; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_LIMIT; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONCURRENCY_LEVEL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PACK_EXTENSIONS; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThrows; +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DfsBlockCachePackExtConfig; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.lib.Config; import org.junit.Test; +@SuppressWarnings("boxing") public class DfsBlockCacheConfigTest { @Test @@ -55,7 +79,6 @@ public void blockSizeNotPowerOfTwoExpectsException() { } @Test - @SuppressWarnings("boxing") public void negativeBlockSizeIsConvertedToDefault() { DfsBlockCacheConfig config = new DfsBlockCacheConfig(); config.setBlockSize(-1); @@ -64,7 +87,6 @@ public void negativeBlockSizeIsConvertedToDefault() { } @Test - @SuppressWarnings("boxing") public void tooSmallBlockSizeIsConvertedToDefault() { DfsBlockCacheConfig config = new DfsBlockCacheConfig(); config.setBlockSize(10); @@ -73,11 +95,295 @@ public void tooSmallBlockSizeIsConvertedToDefault() { } @Test - @SuppressWarnings("boxing") public void validBlockSize() { DfsBlockCacheConfig config = new DfsBlockCacheConfig(); config.setBlockSize(65536); assertThat(config.getBlockSize(), is(65536)); } + + @Test + public void fromConfigs() { + Config config = new Config(); + config.setLong(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_BLOCK_LIMIT, 50 * 1024); + config.setInt(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_BLOCK_SIZE, 1024); + config.setInt(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_CONCURRENCY_LEVEL, 3); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_STREAM_RATIO, "0.5"); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + assertThat(cacheConfig.getBlockLimit(), is(50L * 1024L)); + assertThat(cacheConfig.getBlockSize(), is(1024)); + assertThat(cacheConfig.getConcurrencyLevel(), is(3)); + assertThat(cacheConfig.getStreamRatio(), closeTo(0.5, 0.0001)); + } + + @Test + public void fromConfig_blockLimitNotAMultipleOfBlockSize_throws() { + Config config = new Config(); + config.setLong(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_BLOCK_LIMIT, 1025); + config.setInt(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_BLOCK_SIZE, 1024); + + assertThrows(IllegalArgumentException.class, + () -> new DfsBlockCacheConfig().fromConfig(config)); + } + + @Test + public void fromConfig_streamRatioInvalidFormat_throws() { + Config config = new Config(); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_STREAM_RATIO, "0.a5"); + + assertThrows(IllegalArgumentException.class, + () -> new DfsBlockCacheConfig().fromConfig(config)); + } + + @Test + public void fromConfig_generatesDfsBlockCachePackExtConfigs() { + Config config = new Config(); + addPackExtConfigEntry(config, "pack", List.of(PackExt.PACK), + /* blockLimit= */ 20 * 512, /* blockSize= */ 512); + + addPackExtConfigEntry(config, "bitmap", List.of(PackExt.BITMAP_INDEX), + /* blockLimit= */ 25 * 1024, /* blockSize= */ 1024); + + addPackExtConfigEntry(config, "index", + List.of(PackExt.INDEX, PackExt.OBJECT_SIZE_INDEX, + PackExt.REVERSE_INDEX), + /* blockLimit= */ 30 * 1024, /* blockSize= */ 1024); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + var configs = cacheConfig.getPackExtCacheConfigurations(); + assertThat(configs, hasSize(3)); + var packConfig = getConfigForExt(configs, PackExt.PACK); + assertThat(packConfig.getBlockLimit(), is(20L * 512L)); + assertThat(packConfig.getBlockSize(), is(512)); + + var bitmapConfig = getConfigForExt(configs, PackExt.BITMAP_INDEX); + assertThat(bitmapConfig.getBlockLimit(), is(25L * 1024L)); + assertThat(bitmapConfig.getBlockSize(), is(1024)); + + var indexConfig = getConfigForExt(configs, PackExt.INDEX); + assertThat(indexConfig.getBlockLimit(), is(30L * 1024L)); + assertThat(indexConfig.getBlockSize(), is(1024)); + assertThat(getConfigForExt(configs, PackExt.OBJECT_SIZE_INDEX), + is(indexConfig)); + assertThat(getConfigForExt(configs, PackExt.REVERSE_INDEX), + is(indexConfig)); + } + + @Test + public void fromConfig_withExistingCacheHotMap_configWithPackExtConfigsHasHotMaps() { + Config config = new Config(); + addPackExtConfigEntry(config, "pack", List.of(PackExt.PACK), + /* blockLimit= */ 20 * 512, /* blockSize= */ 512); + + addPackExtConfigEntry(config, "bitmap", List.of(PackExt.BITMAP_INDEX), + /* blockLimit= */ 25 * 1024, /* blockSize= */ 1024); + + addPackExtConfigEntry(config, "index", + List.of(PackExt.INDEX, PackExt.OBJECT_SIZE_INDEX, + PackExt.REVERSE_INDEX), + /* blockLimit= */ 30 * 1024, /* blockSize= */ 1024); + + Map<PackExt, Integer> cacheHotMap = Map.of(PackExt.PACK, 1, + PackExt.BITMAP_INDEX, 2, PackExt.INDEX, 3, PackExt.REFTABLE, 4); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig(); + cacheConfig.setCacheHotMap(cacheHotMap); + cacheConfig.fromConfig(config); + + var configs = cacheConfig.getPackExtCacheConfigurations(); + assertThat(cacheConfig.getCacheHotMap(), is(cacheHotMap)); + assertThat(configs, hasSize(3)); + var packConfig = getConfigForExt(configs, PackExt.PACK); + assertThat(packConfig.getCacheHotMap(), is(Map.of(PackExt.PACK, 1))); + + var bitmapConfig = getConfigForExt(configs, PackExt.BITMAP_INDEX); + assertThat(bitmapConfig.getCacheHotMap(), + is(Map.of(PackExt.BITMAP_INDEX, 2))); + + var indexConfig = getConfigForExt(configs, PackExt.INDEX); + assertThat(indexConfig.getCacheHotMap(), is(Map.of(PackExt.INDEX, 3))); + } + + @Test + public void setCacheHotMap_configWithPackExtConfigs_setsHotMaps() { + Config config = new Config(); + addPackExtConfigEntry(config, "pack", List.of(PackExt.PACK), + /* blockLimit= */ 20 * 512, /* blockSize= */ 512); + + addPackExtConfigEntry(config, "bitmap", List.of(PackExt.BITMAP_INDEX), + /* blockLimit= */ 25 * 1024, /* blockSize= */ 1024); + + addPackExtConfigEntry(config, "index", + List.of(PackExt.INDEX, PackExt.OBJECT_SIZE_INDEX, + PackExt.REVERSE_INDEX), + /* blockLimit= */ 30 * 1024, /* blockSize= */ 1024); + + Map<PackExt, Integer> cacheHotMap = Map.of(PackExt.PACK, 1, + PackExt.BITMAP_INDEX, 2, PackExt.INDEX, 3, PackExt.REFTABLE, 4); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + cacheConfig.setCacheHotMap(cacheHotMap); + + var configs = cacheConfig.getPackExtCacheConfigurations(); + assertThat(cacheConfig.getCacheHotMap(), is(cacheHotMap)); + assertThat(configs, hasSize(3)); + var packConfig = getConfigForExt(configs, PackExt.PACK); + assertThat(packConfig.getCacheHotMap(), is(Map.of(PackExt.PACK, 1))); + + var bitmapConfig = getConfigForExt(configs, PackExt.BITMAP_INDEX); + assertThat(bitmapConfig.getCacheHotMap(), + is(Map.of(PackExt.BITMAP_INDEX, 2))); + + var indexConfig = getConfigForExt(configs, PackExt.INDEX); + assertThat(indexConfig.getCacheHotMap(), is(Map.of(PackExt.INDEX, 3))); + } + + @Test + public void fromConfigs_baseConfigOnly_nameSetFromConfigDfsSubSection() { + Config config = new Config(); + + DfsBlockCacheConfig blockCacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + assertThat(blockCacheConfig.getName(), equalTo(DEFAULT_NAME)); + } + + @Test + public void fromConfigs_namesSetFromConfigDfsCachePrefixSubSections() { + Config config = new Config(); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_STREAM_RATIO, "0.5"); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_CACHE_PREFIX + "name1", + CONFIG_KEY_PACK_EXTENSIONS, PackExt.PACK.name()); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_CACHE_PREFIX + "name2", + CONFIG_KEY_PACK_EXTENSIONS, PackExt.BITMAP_INDEX.name()); + + DfsBlockCacheConfig blockCacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + assertThat(blockCacheConfig.getName(), equalTo("dfs")); + assertThat( + blockCacheConfig.getPackExtCacheConfigurations().get(0) + .getPackExtCacheConfiguration().getName(), + equalTo("dfs.name1")); + assertThat( + blockCacheConfig.getPackExtCacheConfigurations().get(1) + .getPackExtCacheConfiguration().getName(), + equalTo("dfs.name2")); + } + + @Test + public void fromConfigs_dfsBlockCachePackExtConfigWithDuplicateExtensions_throws() { + Config config = new Config(); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_CACHE_PREFIX + "pack1", + CONFIG_KEY_PACK_EXTENSIONS, PackExt.PACK.name()); + + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_CACHE_PREFIX + "pack2", + CONFIG_KEY_PACK_EXTENSIONS, PackExt.PACK.name()); + + assertThrows(IllegalArgumentException.class, + () -> new DfsBlockCacheConfig().fromConfig(config)); + } + + @Test + public void fromConfigs_dfsBlockCachePackExtConfigWithEmptyExtensions_throws() { + Config config = new Config(); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_CACHE_PREFIX + "pack1", + CONFIG_KEY_PACK_EXTENSIONS, ""); + + assertThrows(IllegalArgumentException.class, + () -> new DfsBlockCacheConfig().fromConfig(config)); + } + + @Test + public void fromConfigs_dfsBlockCachePackExtConfigWithNoExtensions_throws() { + Config config = new Config(); + config.setInt(CONFIG_CORE_SECTION, CONFIG_DFS_CACHE_PREFIX + "pack1", + CONFIG_KEY_BLOCK_SIZE, 0); + + assertThrows(IllegalArgumentException.class, + () -> new DfsBlockCacheConfig().fromConfig(config)); + } + + @Test + public void fromConfigs_dfsBlockCachePackExtConfigWithUnknownExtensions_throws() { + Config config = new Config(); + config.setString(CONFIG_CORE_SECTION, + CONFIG_DFS_CACHE_PREFIX + "unknownExt", + CONFIG_KEY_PACK_EXTENSIONS, "NotAKnownExt"); + + assertThrows(IllegalArgumentException.class, + () -> new DfsBlockCacheConfig().fromConfig(config)); + } + + @Test + public void writeConfigurationDebug_writesConfigsToWriter() + throws Exception { + Config config = new Config(); + config.setLong(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_BLOCK_LIMIT, 50 * 1024); + config.setInt(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_BLOCK_SIZE, 1024); + config.setInt(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_CONCURRENCY_LEVEL, 3); + config.setString(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_STREAM_RATIO, "0.5"); + addPackExtConfigEntry(config, "pack", List.of(PackExt.PACK), + /* blockLimit= */ 20 * 512, /* blockSize= */ 512); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + Map<PackExt, Integer> hotmap = Map.of(PackExt.PACK, 10); + cacheConfig.setCacheHotMap(hotmap); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + cacheConfig.print(new PrintWriter(byteArrayOutputStream, true, + StandardCharsets.UTF_8)); + + String writenConfig = byteArrayOutputStream + .toString(StandardCharsets.UTF_8); + + List<String> writenLines = Arrays.asList(writenConfig.split("\n")); + assertThat(writenLines, + equalTo(List.of("Name: dfs", " BlockLimit: " + (50 * 1024), + " BlockSize: 1024", " StreamRatio: 0.5", + " ConcurrencyLevel: 3", + " CacheHotMapEntry: " + PackExt.PACK + " : " + 10, + " Name: dfs.pack", " BlockLimit: " + 20 * 512, + " BlockSize: 512", " StreamRatio: 0.3", + " ConcurrencyLevel: 32", + " CacheHotMapEntry: " + PackExt.PACK + " : " + 10, + " PackExts: " + List.of(PackExt.PACK)))); + } + + private static void addPackExtConfigEntry(Config config, String configName, + List<PackExt> packExts, long blockLimit, int blockSize) { + String packExtConfigName = CONFIG_DFS_CACHE_PREFIX + configName; + config.setString(CONFIG_CORE_SECTION, packExtConfigName, + CONFIG_KEY_PACK_EXTENSIONS, packExts.stream().map(PackExt::name) + .collect(Collectors.joining(" "))); + config.setLong(CONFIG_CORE_SECTION, packExtConfigName, + CONFIG_KEY_BLOCK_LIMIT, blockLimit); + config.setInt(CONFIG_CORE_SECTION, packExtConfigName, + CONFIG_KEY_BLOCK_SIZE, blockSize); + } + + private static DfsBlockCacheConfig getConfigForExt( + List<DfsBlockCachePackExtConfig> configs, PackExt packExt) { + for (DfsBlockCachePackExtConfig config : configs) { + if (config.getPackExts().contains(packExt)) { + return config.getPackExtCacheConfiguration(); + } + } + return null; + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java index fef0563..3c7cc07 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java
@@ -13,20 +13,24 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.time.Duration; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.LongStream; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.LongStream; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DfsBlockCachePackExtConfig; import org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.IndexEventConsumer; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.junit.TestRepository; @@ -39,14 +43,35 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +@RunWith(Parameterized.class) public class DfsBlockCacheTest { @Rule public TestName testName = new TestName(); + private TestRng rng; + private DfsBlockCache cache; + private ExecutorService pool; + private enum CacheType { + SINGLE_TABLE_CLOCK_BLOCK_CACHE, EXT_SPLIT_TABLE_CLOCK_BLOCK_CACHE + } + + @Parameters(name = "cache type: {0}") + public static Iterable<? extends Object> data() { + return Arrays.asList(CacheType.SINGLE_TABLE_CLOCK_BLOCK_CACHE, + CacheType.EXT_SPLIT_TABLE_CLOCK_BLOCK_CACHE); + } + + @Parameter + public CacheType cacheType; + @Before public void setUp() { rng = new TestRng(testName.getMethodName()); @@ -448,8 +473,28 @@ private void resetCache() { } private void resetCache(int concurrencyLevel) { - DfsBlockCache.reconfigure(new DfsBlockCacheConfig().setBlockSize(512) - .setConcurrencyLevel(concurrencyLevel).setBlockLimit(1 << 20)); + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig() + .setBlockSize(512).setConcurrencyLevel(concurrencyLevel) + .setBlockLimit(1 << 20); + switch (cacheType) { + case SINGLE_TABLE_CLOCK_BLOCK_CACHE: + // SINGLE_TABLE_CLOCK_BLOCK_CACHE doesn't modify the config. + break; + case EXT_SPLIT_TABLE_CLOCK_BLOCK_CACHE: + List<DfsBlockCachePackExtConfig> packExtCacheConfigs = new ArrayList<>(); + for (PackExt packExt : PackExt.values()) { + DfsBlockCacheConfig extCacheConfig = new DfsBlockCacheConfig() + .setBlockSize(512).setConcurrencyLevel(concurrencyLevel) + .setBlockLimit(1 << 20) + .setPackExtCacheConfigurations(packExtCacheConfigs); + packExtCacheConfigs.add(new DfsBlockCachePackExtConfig( + EnumSet.of(packExt), extCacheConfig)); + } + cacheConfig.setPackExtCacheConfigurations(packExtCacheConfigs); + break; + } + assertNotNull(cacheConfig); + DfsBlockCache.reconfigure(cacheConfig); cache = DfsBlockCache.getInstance(); }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java index e193de9..00a3760 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java
@@ -6,6 +6,7 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -15,14 +16,18 @@ import static org.junit.Assert.fail; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Arrays; import java.util.Collections; import java.util.concurrent.TimeUnit; + import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.internal.storage.commitgraph.CommitGraphWriter; import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; import org.eclipse.jgit.internal.storage.file.PackBitmapIndex; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.reftable.LogCursor; import org.eclipse.jgit.internal.storage.reftable.RefCursor; import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; import org.eclipse.jgit.internal.storage.reftable.ReftableReader; @@ -36,6 +41,7 @@ import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevBlob; @@ -43,6 +49,7 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.util.GitTimeParser; import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; @@ -1171,6 +1178,7 @@ public void objectSizeIdx_reachableBlob_bigEnough_indexed() throws Exception { gcWithObjectSizeIndex(10); + odb.getReaderOptions().setUseObjectSizeIndex(true); DfsReader reader = odb.newReader(); DfsPackFile gcPack = findFirstBySource(odb.getPacks(), GC); assertTrue(gcPack.hasObjectSizeIndex(reader)); @@ -1191,6 +1199,7 @@ public void objectSizeIdx_reachableBlob_tooSmall_notIndexed() throws Exception { gcWithObjectSizeIndex(10); + odb.getReaderOptions().setUseObjectSizeIndex(true); DfsReader reader = odb.newReader(); DfsPackFile gcPack = findFirstBySource(odb.getPacks(), GC); assertTrue(gcPack.hasObjectSizeIndex(reader)); @@ -1272,6 +1281,87 @@ public void bitmapIndexWrittenDuringGc() throws Exception { bitmapIndex.getXorBitmapCount() > 0); } + @Test + public void gitGCWithRefLogExpire() throws Exception { + String master = "refs/heads/master"; + RevCommit commit0 = commit().message("0").create(); + RevCommit commit1 = commit().message("1").parent(commit0).create(); + git.update(master, commit1); + DfsGarbageCollector gc = new DfsGarbageCollector(repo); + gc.setReftableConfig(new ReftableConfig()); + run(gc); + DfsPackDescription t1 = odb.newPack(INSERT); + Ref next = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, + "refs/heads/next", commit0.copy()); + Instant currentDay = Instant.now(); + Instant ten_days_ago = GitTimeParser.parseInstant("10 days ago"); + Instant twenty_days_ago = GitTimeParser.parseInstant("20 days ago"); + Instant thirty_days_ago = GitTimeParser.parseInstant("30 days ago"); + Instant fifty_days_ago = GitTimeParser.parseInstant("50 days ago"); + final ZoneOffset offset = ZoneOffset.ofHours(-8); + PersonIdent who2 = new PersonIdent("J.Author", "authemail", currentDay, + offset); + PersonIdent who3 = new PersonIdent("J.Author", "authemail", + ten_days_ago, offset); + PersonIdent who4 = new PersonIdent("J.Author", "authemail", + twenty_days_ago, offset); + PersonIdent who5 = new PersonIdent("J.Author", "authemail", + thirty_days_ago, offset); + PersonIdent who6 = new PersonIdent("J.Author", "authemail", + fifty_days_ago, offset); + + try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { + ReftableWriter w = new ReftableWriter(out); + w.setMinUpdateIndex(42); + w.setMaxUpdateIndex(42); + w.begin(); + w.sortAndWriteRefs(Collections.singleton(next)); + w.writeLog("refs/heads/branch", 1, who2, ObjectId.zeroId(),id(2), "Branch Message"); + w.writeLog("refs/heads/branch1", 2, who3, ObjectId.zeroId(),id(3), "Branch Message1"); + w.writeLog("refs/heads/branch2", 2, who4, ObjectId.zeroId(),id(4), "Branch Message2"); + w.writeLog("refs/heads/branch3", 2, who5, ObjectId.zeroId(),id(5), "Branch Message3"); + w.writeLog("refs/heads/branch4", 2, who6, ObjectId.zeroId(),id(6), "Branch Message4"); + w.finish(); + t1.addFileExt(REFTABLE); + t1.setReftableStats(w.getStats()); + } + odb.commitPack(Collections.singleton(t1), null); + + gc = new DfsGarbageCollector(repo); + gc.setReftableConfig(new ReftableConfig()); + // Expire ref log entries older than 30 days + gc.setRefLogExpire(thirty_days_ago); + run(gc); + + // Single GC pack present with all objects. + assertEquals(1, odb.getPacks().length); + DfsPackFile pack = odb.getPacks()[0]; + DfsPackDescription desc = pack.getPackDescription(); + + DfsReftable table = new DfsReftable(DfsBlockCache.getInstance(), desc); + try (DfsReader ctx = odb.newReader(); + ReftableReader rr = table.open(ctx); + RefCursor rc = rr.allRefs(); + LogCursor lc = rr.allLogs()) { + assertTrue(rc.next()); + assertEquals(master, rc.getRef().getName()); + assertEquals(commit1, rc.getRef().getObjectId()); + assertTrue(rc.next()); + assertEquals(next.getName(), rc.getRef().getName()); + assertEquals(commit0, rc.getRef().getObjectId()); + assertFalse(rc.next()); + assertTrue(lc.next()); + assertEquals(lc.getRefName(),"refs/heads/branch"); + assertTrue(lc.next()); + assertEquals(lc.getRefName(),"refs/heads/branch1"); + assertTrue(lc.next()); + assertEquals(lc.getRefName(),"refs/heads/branch2"); + // Old entries are purged + assertFalse(lc.next()); + } + } + + private RevCommit commitChain(RevCommit parent, int length) throws Exception { for (int i = 0; i < length; i++) { @@ -1361,4 +1451,12 @@ private int countPacks(PackSource source) throws IOException { } return cnt; } + private static ObjectId id(int i) { + byte[] buf = new byte[OBJECT_ID_LENGTH]; + buf[0] = (byte) (i & 0xff); + buf[1] = (byte) ((i >>> 8) & 0xff); + buf[2] = (byte) ((i >>> 16) & 0xff); + buf[3] = (byte) (i >>> 24); + return ObjectId.fromRaw(buf); + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java index b84a0b0..0b558ed 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
@@ -295,6 +295,7 @@ public void testObjectSizePopulated() throws IOException { public void testObjectSizeIndexOnInsert() throws IOException { db.getConfig().setInt(CONFIG_PACK_SECTION, null, CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, 0); + db.getObjectDatabase().getReaderOptions().setUseObjectSizeIndex(true); byte[] contents = Constants.encode("foo"); ObjectId fooId;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java index c516e30..c3b6aa8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java
@@ -12,13 +12,18 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.Arrays; +import java.util.Optional; import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Before; import org.junit.Test; @@ -98,6 +103,40 @@ public void testEstimateGcPackSizeWithAnExistingGcPack() throws Exception { pack.getPackDescription().getEstimatedPackSize()); } + @Test + public void testObjectSizeIndexWritten() throws Exception { + writeObjectSizeIndex(repo, true); + RevCommit commit0 = commit().message("0").create(); + RevCommit commit1 = commit().message("1").parent(commit0).create(); + git.update("master", commit1); + + compact(); + + Optional<DfsPackFile> compactPack = Arrays.stream(odb.getPacks()) + .filter(pack -> pack.getPackDescription() + .getPackSource() == COMPACT) + .findFirst(); + assertTrue(compactPack.isPresent()); + assertTrue(compactPack.get().getPackDescription().hasFileExt(OBJECT_SIZE_INDEX)); + } + + @Test + public void testObjectSizeIndexNotWritten() throws Exception { + writeObjectSizeIndex(repo, false); + RevCommit commit0 = commit().message("0").create(); + RevCommit commit1 = commit().message("1").parent(commit0).create(); + git.update("master", commit1); + + compact(); + + Optional<DfsPackFile> compactPack = Arrays.stream(odb.getPacks()) + .filter(pack -> pack.getPackDescription() + .getPackSource() == COMPACT) + .findFirst(); + assertTrue(compactPack.isPresent()); + assertFalse(compactPack.get().getPackDescription().hasFileExt(OBJECT_SIZE_INDEX)); + } + private TestRepository<InMemoryRepository>.CommitBuilder commit() { return git.commit(); } @@ -108,4 +147,9 @@ private void compact() throws IOException { compactor.compact(null); odb.clearCache(); } + + private static void writeObjectSizeIndex(DfsRepository repo, boolean should) { + repo.getConfig().setInt(ConfigConstants.CONFIG_PACK_SECTION, null, + ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, should ? 0 : -1); + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java index d21e51f..9680019 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileTest.java
@@ -41,6 +41,7 @@ import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.ReceiveCommand; import org.junit.Before; import org.junit.Test; @@ -126,6 +127,7 @@ public void testLoadObjectSizeIndex() throws IOException { setObjectSizeIndexMinBytes(0); ObjectId blobId = setupPack(512, 800); + db.getObjectDatabase().getReaderOptions().setUseObjectSizeIndex(true); DfsReader reader = db.getObjectDatabase().newReader(); DfsPackFile pack = db.getObjectDatabase().getPacks()[0]; assertTrue(pack.hasObjectSizeIndex(reader)); @@ -308,7 +310,7 @@ private ObjectId setupPack(int bs, int ps) throws IOException { private void assertPackSize() throws IOException { try (DfsReader ctx = db.getObjectDatabase().newReader(); - PackWriter pw = new PackWriter(ctx); + PackWriter pw = new PackWriter(new PackConfig(), ctx); ByteArrayOutputStream os = new ByteArrayOutputStream(); PackOutputStream out = new PackOutputStream( NullProgressMonitor.INSTANCE, os, pw)) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackParserTest.java index 130af27..c1cd231 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackParserTest.java
@@ -61,6 +61,7 @@ public void parse_writeObjSizeIdx() throws IOException { ins.flush(); } + repo.getObjectDatabase().getReaderOptions().setUseObjectSizeIndex(true); DfsReader reader = repo.getObjectDatabase().newReader(); PackList packList = repo.getObjectDatabase().getPackList(); assertEquals(1, packList.packs.length);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsReaderTest.java index 254184e..a0c2289 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsReaderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsReaderTest.java
@@ -37,6 +37,8 @@ public class DfsReaderTest { @Before public void setUp() { db = new InMemoryRepository(new DfsRepositoryDescription("test")); + // These tests assume the object size index is enabled. + db.getObjectDatabase().getReaderOptions().setUseObjectSizeIndex(true); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java new file mode 100644 index 0000000..e7627bc --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java
@@ -0,0 +1,679 @@ +/* + * Copyright (c) 2024, 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.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +import java.util.EnumSet; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCache.Ref; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCache.RefLoader; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DfsBlockCachePackExtConfig; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.junit.Test; +import org.mockito.Mockito; + +@SuppressWarnings({ "boxing", "unchecked" }) +public class PackExtBlockCacheTableTest { + private static final String CACHE_NAME = "CacheName"; + + @Test + public void fromBlockCacheConfigs_createsDfsPackExtBlockCacheTables() { + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig(); + cacheConfig.setPackExtCacheConfigurations( + List.of(new DfsBlockCachePackExtConfig(EnumSet.of(PackExt.PACK), + new DfsBlockCacheConfig()))); + assertNotNull( + PackExtBlockCacheTable.fromBlockCacheConfigs(cacheConfig)); + } + + @Test + public void fromBlockCacheConfigs_noPackExtConfigurationGiven_packExtCacheConfigurationsIsEmpty_throws() { + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig(); + cacheConfig.setPackExtCacheConfigurations(List.of()); + assertThrows(IllegalArgumentException.class, + () -> PackExtBlockCacheTable + .fromBlockCacheConfigs(cacheConfig)); + } + + @Test + public void hasBlock0_packExtMapsToCacheTable_callsBitmapIndexCacheTable() { + DfsStreamKey streamKey = new TestKey(PackExt.BITMAP_INDEX); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.hasBlock0(any(DfsStreamKey.class))) + .thenReturn(true); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertTrue(tables.hasBlock0(streamKey)); + } + + @Test + public void hasBlock0_packExtDoesNotMapToCacheTable_callsDefaultCache() { + DfsStreamKey streamKey = new TestKey(PackExt.PACK); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.hasBlock0(any(DfsStreamKey.class))) + .thenReturn(true); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertTrue(tables.hasBlock0(streamKey)); + } + + @Test + public void getOrLoad_packExtMapsToCacheTable_callsBitmapIndexCacheTable() + throws Exception { + BlockBasedFile blockBasedFile = new BlockBasedFile(null, + mock(DfsPackDescription.class), PackExt.BITMAP_INDEX) { + // empty + }; + DfsBlock dfsBlock = mock(DfsBlock.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.getOrLoad(any(BlockBasedFile.class), + anyLong(), any(DfsReader.class), + any(DfsBlockCache.ReadableChannelSupplier.class))) + .thenReturn(mock(DfsBlock.class)); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.getOrLoad(any(BlockBasedFile.class), + anyLong(), any(DfsReader.class), + any(DfsBlockCache.ReadableChannelSupplier.class))) + .thenReturn(dfsBlock); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat( + tables.getOrLoad(blockBasedFile, 0, mock(DfsReader.class), + mock(DfsBlockCache.ReadableChannelSupplier.class)), + sameInstance(dfsBlock)); + } + + @Test + public void getOrLoad_packExtDoesNotMapToCacheTable_callsDefaultCache() + throws Exception { + BlockBasedFile blockBasedFile = new BlockBasedFile(null, + mock(DfsPackDescription.class), PackExt.PACK) { + // empty + }; + DfsBlock dfsBlock = mock(DfsBlock.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.getOrLoad(any(BlockBasedFile.class), + anyLong(), any(DfsReader.class), + any(DfsBlockCache.ReadableChannelSupplier.class))) + .thenReturn(dfsBlock); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.getOrLoad(any(BlockBasedFile.class), + anyLong(), any(DfsReader.class), + any(DfsBlockCache.ReadableChannelSupplier.class))) + .thenReturn(mock(DfsBlock.class)); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat( + tables.getOrLoad(blockBasedFile, 0, mock(DfsReader.class), + mock(DfsBlockCache.ReadableChannelSupplier.class)), + sameInstance(dfsBlock)); + } + + @Test + public void getOrLoadRef_packExtMapsToCacheTable_callsBitmapIndexCacheTable() + throws Exception { + Ref<Integer> ref = mock(Ref.class); + DfsStreamKey dfsStreamKey = new TestKey(PackExt.BITMAP_INDEX); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.getOrLoadRef(any(DfsStreamKey.class), + anyLong(), any(RefLoader.class))).thenReturn(mock(Ref.class)); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.getOrLoadRef(any(DfsStreamKey.class), + anyLong(), any(RefLoader.class))).thenReturn(ref); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.getOrLoadRef(dfsStreamKey, 0, mock(RefLoader.class)), + sameInstance(ref)); + } + + @Test + public void getOrLoadRef_packExtDoesNotMapToCacheTable_callsDefaultCache() + throws Exception { + Ref<Integer> ref = mock(Ref.class); + DfsStreamKey dfsStreamKey = new TestKey(PackExt.PACK); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.getOrLoadRef(any(DfsStreamKey.class), + anyLong(), any(RefLoader.class))).thenReturn(ref); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.getOrLoadRef(any(DfsStreamKey.class), + anyLong(), any(RefLoader.class))).thenReturn(mock(Ref.class)); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.getOrLoadRef(dfsStreamKey, 0, mock(RefLoader.class)), + sameInstance(ref)); + } + + @Test + public void putDfsBlock_packExtMapsToCacheTable_callsBitmapIndexCacheTable() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.BITMAP_INDEX); + DfsBlock dfsBlock = new DfsBlock(dfsStreamKey, 0, new byte[0]); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + tables.put(dfsBlock); + Mockito.verify(bitmapIndexCacheTable, times(1)).put(dfsBlock); + } + + @Test + public void putDfsBlock_packExtDoesNotMapToCacheTable_callsDefaultCache() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.PACK); + DfsBlock dfsBlock = new DfsBlock(dfsStreamKey, 0, new byte[0]); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + tables.put(dfsBlock); + Mockito.verify(defaultBlockCacheTable, times(1)).put(dfsBlock); + } + + @Test + public void putDfsStreamKey_packExtMapsToCacheTable_callsBitmapIndexCacheTable() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.BITMAP_INDEX); + Ref<Integer> ref = mock(Ref.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.put(any(DfsStreamKey.class), anyLong(), + anyLong(), anyInt())).thenReturn(mock(Ref.class)); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.put(any(DfsStreamKey.class), anyLong(), + anyLong(), anyInt())).thenReturn(ref); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.put(dfsStreamKey, 0, 0, 0), sameInstance(ref)); + } + + @Test + public void putDfsStreamKey_packExtDoesNotMapToCacheTable_callsDefaultCache() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.PACK); + Ref<Integer> ref = mock(Ref.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.put(any(DfsStreamKey.class), anyLong(), + anyLong(), anyInt())).thenReturn(ref); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.put(any(DfsStreamKey.class), anyLong(), + anyLong(), anyInt())).thenReturn(mock(Ref.class)); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.put(dfsStreamKey, 0, 0, 0), sameInstance(ref)); + } + + @Test + public void putRef_packExtMapsToCacheTable_callsBitmapIndexCacheTable() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.BITMAP_INDEX); + Ref<Integer> ref = mock(Ref.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.putRef(any(DfsStreamKey.class), anyLong(), + anyInt())).thenReturn(mock(Ref.class)); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.putRef(any(DfsStreamKey.class), anyLong(), + anyInt())).thenReturn(ref); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.putRef(dfsStreamKey, 0, 0), sameInstance(ref)); + } + + @Test + public void putRef_packExtDoesNotMapToCacheTable_callsDefaultCache() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.PACK); + Ref<Integer> ref = mock(Ref.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.putRef(any(DfsStreamKey.class), anyLong(), + anyInt())).thenReturn(ref); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.putRef(any(DfsStreamKey.class), anyLong(), + anyInt())).thenReturn(mock(Ref.class)); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.putRef(dfsStreamKey, 0, 0), sameInstance(ref)); + } + + @Test + public void contains_packExtMapsToCacheTable_callsBitmapIndexCacheTable() { + DfsStreamKey streamKey = new TestKey(PackExt.BITMAP_INDEX); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.contains(any(DfsStreamKey.class), anyLong())) + .thenReturn(true); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertTrue(tables.contains(streamKey, 0)); + } + + @Test + public void contains_packExtDoesNotMapToCacheTable_callsDefaultCache() { + DfsStreamKey streamKey = new TestKey(PackExt.PACK); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.contains(any(DfsStreamKey.class), + anyLong())).thenReturn(true); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertTrue(tables.contains(streamKey, 0)); + } + + @Test + public void get_packExtMapsToCacheTable_callsBitmapIndexCacheTable() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.BITMAP_INDEX); + Ref<Integer> ref = mock(Ref.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.get(any(DfsStreamKey.class), anyLong())) + .thenReturn(mock(Ref.class)); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.get(any(DfsStreamKey.class), anyLong())) + .thenReturn(ref); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.get(dfsStreamKey, 0), sameInstance(ref)); + } + + @Test + public void get_packExtDoesNotMapToCacheTable_callsDefaultCache() { + DfsStreamKey dfsStreamKey = new TestKey(PackExt.PACK); + Ref<Integer> ref = mock(Ref.class); + DfsBlockCacheTable defaultBlockCacheTable = mock( + DfsBlockCacheTable.class); + when(defaultBlockCacheTable.get(any(DfsStreamKey.class), anyLong())) + .thenReturn(ref); + DfsBlockCacheTable bitmapIndexCacheTable = mock( + DfsBlockCacheTable.class); + when(bitmapIndexCacheTable.get(any(DfsStreamKey.class), anyLong())) + .thenReturn(mock(Ref.class)); + + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + defaultBlockCacheTable, + Map.of(PackExt.BITMAP_INDEX, bitmapIndexCacheTable)); + + assertThat(tables.get(dfsStreamKey, 0), sameInstance(ref)); + } + + @Test + public void getName() { + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( + cacheTableWithStats(/* name= */ "defaultName", packStats), + Map.of(PackExt.PACK, cacheTableWithStats(/* name= */ "packName", + packStats))); + + assertThat(tables.getName(), equalTo("defaultName,packName")); + } + + @Test + public void getAllBlockCacheStats() { + String defaultTableName = "default table"; + DfsBlockCacheStats defaultStats = new DfsBlockCacheStats( + defaultTableName); + incrementCounter(4, + () -> defaultStats.incrementHit(new TestKey(PackExt.REFTABLE))); + + String packTableName = "pack table"; + DfsBlockCacheStats packStats = new DfsBlockCacheStats(packTableName); + incrementCounter(5, + () -> packStats.incrementHit(new TestKey(PackExt.PACK))); + + String bitmapTableName = "bitmap table"; + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats( + bitmapTableName); + incrementCounter(6, () -> bitmapStats + .incrementHit(new TestKey(PackExt.BITMAP_INDEX))); + + DfsBlockCacheTable defaultTable = cacheTableWithStats(defaultStats); + DfsBlockCacheTable packTable = cacheTableWithStats(packStats); + DfsBlockCacheTable bitmapTable = cacheTableWithStats(bitmapStats); + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(defaultTable, Map.of(PackExt.PACK, packTable, + PackExt.BITMAP_INDEX, bitmapTable)); + + List<BlockCacheStats> statsList = tables.getBlockCacheStats(); + assertThat(statsList, hasSize(3)); + + long[] defaultTableHitCounts = createEmptyStatsArray(); + defaultTableHitCounts[PackExt.REFTABLE.getPosition()] = 4; + assertArrayEquals( + getCacheStatsByName(statsList, defaultTableName).getHitCount(), + defaultTableHitCounts); + + long[] packTableHitCounts = createEmptyStatsArray(); + packTableHitCounts[PackExt.PACK.getPosition()] = 5; + assertArrayEquals( + getCacheStatsByName(statsList, packTableName).getHitCount(), + packTableHitCounts); + + long[] bitmapHitCounts = createEmptyStatsArray(); + bitmapHitCounts[PackExt.BITMAP_INDEX.getPosition()] = 6; + assertArrayEquals( + getCacheStatsByName(statsList, bitmapTableName).getHitCount(), + bitmapHitCounts); + } + + @Test + public void getBlockCacheStats_getCurrentSize_consolidatesAllTableCurrentSizes() { + long[] currentSizes = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + packStats.addToLiveBytes(new TestKey(PackExt.PACK), 5); + currentSizes[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + bitmapStats.addToLiveBytes(new TestKey(PackExt.BITMAP_INDEX), 6); + currentSizes[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + indexStats.addToLiveBytes(new TestKey(PackExt.INDEX), 7); + currentSizes[PackExt.INDEX.getPosition()] = 7; + + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(cacheTableWithStats(packStats), + Map.of(PackExt.BITMAP_INDEX, + cacheTableWithStats(bitmapStats), PackExt.INDEX, + cacheTableWithStats(indexStats))); + + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getCurrentSize(), + currentSizes); + } + + @Test + public void getBlockCacheStats_GetHitCount_consolidatesAllTableHitCounts() { + long[] hitCounts = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementHit(new TestKey(PackExt.PACK))); + hitCounts[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> bitmapStats + .incrementHit(new TestKey(PackExt.BITMAP_INDEX))); + hitCounts[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementHit(new TestKey(PackExt.INDEX))); + hitCounts[PackExt.INDEX.getPosition()] = 7; + + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(cacheTableWithStats(packStats), + Map.of(PackExt.BITMAP_INDEX, + cacheTableWithStats(bitmapStats), PackExt.INDEX, + cacheTableWithStats(indexStats))); + + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getHitCount(), + hitCounts); + } + + @Test + public void getBlockCacheStats_getMissCount_consolidatesAllTableMissCounts() { + long[] missCounts = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementMiss(new TestKey(PackExt.PACK))); + missCounts[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> bitmapStats + .incrementMiss(new TestKey(PackExt.BITMAP_INDEX))); + missCounts[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementMiss(new TestKey(PackExt.INDEX))); + missCounts[PackExt.INDEX.getPosition()] = 7; + + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(cacheTableWithStats(packStats), + Map.of(PackExt.BITMAP_INDEX, + cacheTableWithStats(bitmapStats), PackExt.INDEX, + cacheTableWithStats(indexStats))); + + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getMissCount(), + missCounts); + } + + @Test + public void getBlockCacheStats_getTotalRequestCount_consolidatesAllTableTotalRequestCounts() { + long[] totalRequestCounts = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, () -> { + packStats.incrementHit(new TestKey(PackExt.PACK)); + packStats.incrementMiss(new TestKey(PackExt.PACK)); + }); + totalRequestCounts[PackExt.PACK.getPosition()] = 10; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> { + bitmapStats.incrementHit(new TestKey(PackExt.BITMAP_INDEX)); + bitmapStats.incrementMiss(new TestKey(PackExt.BITMAP_INDEX)); + }); + totalRequestCounts[PackExt.BITMAP_INDEX.getPosition()] = 12; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, () -> { + indexStats.incrementHit(new TestKey(PackExt.INDEX)); + indexStats.incrementMiss(new TestKey(PackExt.INDEX)); + }); + totalRequestCounts[PackExt.INDEX.getPosition()] = 14; + + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(cacheTableWithStats(packStats), + Map.of(PackExt.BITMAP_INDEX, + cacheTableWithStats(bitmapStats), PackExt.INDEX, + cacheTableWithStats(indexStats))); + + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()) + .getTotalRequestCount(), totalRequestCounts); + } + + @Test + public void getBlockCacheStats_getHitRatio_consolidatesAllTableHitRatios() { + long[] hitRatios = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementHit(new TestKey(PackExt.PACK))); + hitRatios[PackExt.PACK.getPosition()] = 100; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> { + bitmapStats.incrementHit(new TestKey(PackExt.BITMAP_INDEX)); + bitmapStats.incrementMiss(new TestKey(PackExt.BITMAP_INDEX)); + }); + hitRatios[PackExt.BITMAP_INDEX.getPosition()] = 50; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementMiss(new TestKey(PackExt.INDEX))); + hitRatios[PackExt.INDEX.getPosition()] = 0; + + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(cacheTableWithStats(packStats), + Map.of(PackExt.BITMAP_INDEX, + cacheTableWithStats(bitmapStats), PackExt.INDEX, + cacheTableWithStats(indexStats))); + + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getHitRatio(), + hitRatios); + } + + @Test + public void getBlockCacheStats_getEvictions_consolidatesAllTableEvictions() { + long[] evictions = createEmptyStatsArray(); + + DfsBlockCacheStats packStats = new DfsBlockCacheStats(); + incrementCounter(5, + () -> packStats.incrementEvict(new TestKey(PackExt.PACK))); + evictions[PackExt.PACK.getPosition()] = 5; + + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats(); + incrementCounter(6, () -> bitmapStats + .incrementEvict(new TestKey(PackExt.BITMAP_INDEX))); + evictions[PackExt.BITMAP_INDEX.getPosition()] = 6; + + DfsBlockCacheStats indexStats = new DfsBlockCacheStats(); + incrementCounter(7, + () -> indexStats.incrementEvict(new TestKey(PackExt.INDEX))); + evictions[PackExt.INDEX.getPosition()] = 7; + + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(cacheTableWithStats(packStats), + Map.of(PackExt.BITMAP_INDEX, + cacheTableWithStats(bitmapStats), PackExt.INDEX, + cacheTableWithStats(indexStats))); + + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getEvictions(), + evictions); + } + + private BlockCacheStats getCacheStatsByName( + List<BlockCacheStats> blockCacheStats, String name) { + for (BlockCacheStats entry : blockCacheStats) { + if (entry.getName().equals(name)) { + return entry; + } + } + return null; + } + + private static void incrementCounter(int amount, Runnable fn) { + for (int i = 0; i < amount; i++) { + fn.run(); + } + } + + private static long[] createEmptyStatsArray() { + return new long[PackExt.values().length]; + } + + private static DfsBlockCacheTable cacheTableWithStats( + BlockCacheStats dfsBlockCacheStats) { + return cacheTableWithStats(CACHE_NAME, dfsBlockCacheStats); + } + + private static DfsBlockCacheTable cacheTableWithStats(String name, + BlockCacheStats dfsBlockCacheStats) { + DfsBlockCacheTable cacheTable = mock(DfsBlockCacheTable.class); + when(cacheTable.getName()).thenReturn(name); + when(cacheTable.getBlockCacheStats()) + .thenReturn(List.of(dfsBlockCacheStats)); + return cacheTable; + } + + private static class TestKey extends DfsStreamKey { + TestKey(PackExt packExt) { + super(0, packExt); + } + + @Override + public boolean equals(Object o) { + return false; + } + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java index bd36337..41a33df 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
@@ -29,6 +29,7 @@ import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.AbbreviatedObjectId;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BasePackWriterTest.java similarity index 99% rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BasePackWriterTest.java index 24a81b6..92d7465 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BasePackWriterTest.java
@@ -66,7 +66,7 @@ import org.junit.Test; import org.mockito.Mockito; -public class PackWriterTest extends SampleDataRepositoryTestCase { +public class BasePackWriterTest extends SampleDataRepositoryTestCase { private static final List<RevObject> EMPTY_LIST_REVS = Collections .<RevObject> emptyList();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java index daf4382..a0afc3e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
@@ -171,7 +171,7 @@ public void packedRefsFileIsSorted() throws IOException { assertEquals(c2.getResult(), ReceiveCommand.Result.OK); } - File packed = new File(diskRepo.getDirectory(), "packed-refs"); + File packed = new File(diskRepo.getCommonDirectory(), "packed-refs"); String packedStr = new String(Files.readAllBytes(packed.toPath()), UTF_8); @@ -1263,7 +1263,7 @@ private Map<String, ReflogEntry> getLastReflogs(String... names) } private ReflogEntry getLastReflog(String name) throws IOException { - ReflogReader r = diskRepo.getReflogReader(name); + ReflogReader r = diskRepo.getRefDatabase().getReflogReader(name); if (r == null) { return null; }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java index 32342e3..5756b41 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import java.io.File; import java.io.FileOutputStream; @@ -33,8 +34,15 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; - import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; @@ -51,6 +59,10 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FS.ExecutionResult; +import org.eclipse.jgit.util.RawParseUtils; +import org.eclipse.jgit.util.TemporaryBuffer; import org.junit.Test; public class FileReftableTest extends SampleDataRepositoryTestCase { @@ -66,6 +78,30 @@ public void setUp() throws Exception { @SuppressWarnings("boxing") @Test + public void testReloadIfNecessary() throws Exception { + ObjectId id = db.resolve("master"); + try (FileRepository repo1 = new FileRepository(db.getDirectory()); + FileRepository repo2 = new FileRepository(db.getDirectory())) { + ((FileReftableDatabase) repo1.getRefDatabase()) + .setAutoRefresh(true); + ((FileReftableDatabase) repo2.getRefDatabase()) + .setAutoRefresh(true); + FileRepository repos[] = { repo1, repo2 }; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 2; j++) { + FileRepository repo = repos[j]; + RefUpdate u = repo.getRefDatabase().newUpdate( + String.format("branch%d", i * 10 + j), false); + u.setNewObjectId(id); + RefUpdate.Result r = u.update(); + assertEquals(Result.NEW, r); + } + } + } + } + + @SuppressWarnings("boxing") + @Test public void testRacyReload() throws Exception { ObjectId id = db.resolve("master"); int retry = 0; @@ -87,13 +123,61 @@ public void testRacyReload() throws Exception { u.setNewObjectId(id); r = u.update(); - assertEquals(r, Result.NEW); + assertEquals(Result.NEW, r); } } } // only the first one succeeds - assertEquals(retry, 19); + assertEquals(19, retry); + } + } + + @Test + public void testConcurrentRacyReload() throws Exception { + ObjectId id = db.resolve("master"); + final CyclicBarrier barrier = new CyclicBarrier(2); + + class UpdateRef implements Callable<RefUpdate.Result> { + + private RefUpdate u; + + UpdateRef(FileRepository repo, String branchName) + throws IOException { + u = repo.getRefDatabase().newUpdate(branchName, + false); + u.setNewObjectId(id); + } + + @Override + public RefUpdate.Result call() throws Exception { + barrier.await(); // wait for the other thread to prepare + return u.update(); + } + } + + ExecutorService pool = Executors.newFixedThreadPool(2); + try (FileRepository repo1 = new FileRepository(db.getDirectory()); + FileRepository repo2 = new FileRepository(db.getDirectory())) { + ((FileReftableDatabase) repo1.getRefDatabase()) + .setAutoRefresh(true); + ((FileReftableDatabase) repo2.getRefDatabase()) + .setAutoRefresh(true); + for (int i = 0; i < 10; i++) { + String branchName = String.format("branch%d", + Integer.valueOf(i)); + Future<RefUpdate.Result> ru1 = pool + .submit(new UpdateRef(repo1, branchName)); + Future<RefUpdate.Result> ru2 = pool + .submit(new UpdateRef(repo2, branchName)); + assertTrue((ru1.get() == Result.NEW + && ru2.get() == Result.LOCK_FAILURE) + || (ru1.get() == Result.LOCK_FAILURE + && ru2.get() == Result.NEW)); + } + } finally { + pool.shutdown(); + pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); } } @@ -105,13 +189,13 @@ public void testCompactFully() throws Exception { RefUpdate u = db.updateRef("refs/heads/master"); u.setForceUpdate(true); u.setNewObjectId((i%2) == 0 ? c1 : c2); - assertEquals(u.update(), FORCED); + assertEquals(FORCED, u.update()); } File tableDir = new File(db.getDirectory(), Constants.REFTABLE); assertTrue(tableDir.listFiles().length > 2); ((FileReftableDatabase)db.getRefDatabase()).compactFully(); - assertEquals(tableDir.listFiles().length,2); + assertEquals(2, tableDir.listFiles().length); } @Test @@ -171,9 +255,10 @@ public void testConvertToRefdirReflog() throws Exception { v.update(); db.convertToPackedRefs(true, false); - List<ReflogEntry> logs = db.getReflogReader("refs/heads/master").getReverseEntries(2); - assertEquals(logs.get(0).getComment(), "banana"); - assertEquals(logs.get(1).getComment(), "apple"); + List<ReflogEntry> logs = db.getRefDatabase() + .getReflogReader("refs/heads/master").getReverseEntries(2); + assertEquals("banana", logs.get(0).getComment()); + assertEquals("apple", logs.get(1).getComment()); } @Test @@ -185,8 +270,9 @@ public void testBatchrefUpdate() throws Exception { ReceiveCommand rc1 = new ReceiveCommand(ObjectId.zeroId(), cur, "refs/heads/batch1"); ReceiveCommand rc2 = new ReceiveCommand(ObjectId.zeroId(), prev, "refs/heads/batch2"); String msg = "message"; + RefDatabase refDb = db.getRefDatabase(); try (RevWalk rw = new RevWalk(db)) { - db.getRefDatabase().newBatchUpdate() + refDb.newBatchUpdate() .addCommand(rc1, rc2) .setAtomic(true) .setRefLogIdent(person) @@ -194,15 +280,17 @@ public void testBatchrefUpdate() throws Exception { .execute(rw, NullProgressMonitor.INSTANCE); } - assertEquals(rc1.getResult(), ReceiveCommand.Result.OK); - assertEquals(rc2.getResult(), ReceiveCommand.Result.OK); + assertEquals(ReceiveCommand.Result.OK, rc1.getResult()); + assertEquals(ReceiveCommand.Result.OK, rc2.getResult()); - ReflogEntry e = db.getReflogReader("refs/heads/batch1").getLastEntry(); + ReflogEntry e = refDb.getReflogReader("refs/heads/batch1") + .getLastEntry(); assertEquals(msg, e.getComment()); assertEquals(person, e.getWho()); assertEquals(cur, e.getNewId()); - e = db.getReflogReader("refs/heads/batch2").getLastEntry(); + e = refDb.getReflogReader("refs/heads/batch2") + .getLastEntry(); assertEquals(msg, e.getComment()); assertEquals(person, e.getWho()); assertEquals(prev, e.getNewId()); @@ -267,7 +355,7 @@ public void testDelete() throws Exception { RefUpdate up = db.getRefDatabase().newUpdate("refs/heads/a", false); up.setForceUpdate(true); RefUpdate.Result res = up.delete(); - assertEquals(res, FORCED); + assertEquals(FORCED, res); assertNull(db.exactRef("refs/heads/a")); } @@ -309,7 +397,7 @@ public void testUpdateRefDetached() throws Exception { // the branch HEAD referred to is left untouched assertEquals(pid, db.resolve("refs/heads/master")); - ReflogReader reflogReader = db.getReflogReader("HEAD"); + ReflogReader reflogReader = db.getRefDatabase().getReflogReader("HEAD"); ReflogEntry e = reflogReader.getReverseEntries().get(0); assertEquals(ppid, e.getNewId()); assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress()); @@ -330,12 +418,13 @@ public void testWriteReflog() throws Exception { updateRef.setForceUpdate(true); RefUpdate.Result update = updateRef.update(); assertEquals(FORCED, update); // internal - ReflogReader r = db.getReflogReader("refs/heads/master"); + ReflogReader r = db.getRefDatabase() + .getReflogReader("refs/heads/master"); ReflogEntry e = r.getLastEntry(); - assertEquals(e.getNewId(), pid); - assertEquals(e.getComment(), "REFLOG!: FORCED"); - assertEquals(e.getWho(), person); + assertEquals(pid, e.getNewId()); + assertEquals("REFLOG!: FORCED", e.getComment()); + assertEquals(person, e.getWho()); } @Test @@ -352,10 +441,11 @@ public void testLooseDelete() throws IOException { ref = db.updateRef(newRef); ref.setNewObjectId(db.resolve(Constants.HEAD)); - assertEquals(ref.delete(), RefUpdate.Result.NO_CHANGE); + assertEquals(RefUpdate.Result.NO_CHANGE, ref.delete()); // Differs from RefupdateTest. Deleting a loose ref leaves reflog trail. - ReflogReader reader = db.getReflogReader("refs/heads/abc"); + ReflogReader reader = db.getRefDatabase() + .getReflogReader("refs/heads/abc"); assertEquals(ObjectId.zeroId(), reader.getReverseEntry(1).getOldId()); assertEquals(nonZero, reader.getReverseEntry(1).getNewId()); assertEquals(nonZero, reader.getReverseEntry(0).getOldId()); @@ -382,8 +472,9 @@ public void testNoCacheObjectIdSubclass() throws IOException { assertNotSame(newid, r.getObjectId()); assertSame(ObjectId.class, r.getObjectId().getClass()); assertEquals(newid, r.getObjectId()); - List<ReflogEntry> reverseEntries1 = db.getReflogReader("refs/heads/abc") - .getReverseEntries(); + RefDatabase refDb = db.getRefDatabase(); + List<ReflogEntry> reverseEntries1 = refDb + .getReflogReader("refs/heads/abc").getReverseEntries(); ReflogEntry entry1 = reverseEntries1.get(0); assertEquals(1, reverseEntries1.size()); assertEquals(ObjectId.zeroId(), entry1.getOldId()); @@ -392,7 +483,7 @@ public void testNoCacheObjectIdSubclass() throws IOException { assertEquals(new PersonIdent(db).toString(), entry1.getWho().toString()); assertEquals("", entry1.getComment()); - List<ReflogEntry> reverseEntries2 = db.getReflogReader("HEAD") + List<ReflogEntry> reverseEntries2 = refDb.getReflogReader("HEAD") .getReverseEntries(); assertEquals(0, reverseEntries2.size()); } @@ -431,7 +522,7 @@ public void writeUnbornHead() throws Exception { Ref head = db.exactRef("HEAD"); assertTrue(head.isSymbolic()); - assertEquals(head.getTarget().getName(), "refs/heads/unborn"); + assertEquals("refs/heads/unborn", head.getTarget().getName()); } /** @@ -455,7 +546,7 @@ public void testUpdateRefDetachedUnbornHead() throws Exception { // the branch HEAD referred to is left untouched assertNull(db.resolve("refs/heads/unborn")); - ReflogReader reflogReader = db.getReflogReader("HEAD"); + ReflogReader reflogReader = db.getRefDatabase().getReflogReader("HEAD"); ReflogEntry e = reflogReader.getReverseEntries().get(0); assertEquals(ObjectId.zeroId(), e.getOldId()); assertEquals(ppid, e.getNewId()); @@ -499,7 +590,7 @@ public void testRenameCurrentBranch() throws IOException { names.add("refs/heads/new/name"); for (String nm : names) { - ReflogReader rd = db.getReflogReader(nm); + ReflogReader rd = db.getRefDatabase().getReflogReader(nm); assertNotNull(rd); ReflogEntry last = rd.getLastEntry(); ObjectId id = last.getNewId(); @@ -573,10 +664,10 @@ public void compactFully() throws Exception { assertTrue(res == Result.NEW || res == FORCED); } - assertEquals(refDb.exactRef(refName).getObjectId(), bId); + assertEquals(bId, refDb.exactRef(refName).getObjectId()); assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment())); refDb.compactFully(); - assertEquals(refDb.exactRef(refName).getObjectId(), bId); + assertEquals(bId, refDb.exactRef(refName).getObjectId()); assertTrue(randomStr.equals(refDb.getReflogReader(refName).getReverseEntry(1).getComment())); } @@ -644,6 +735,54 @@ public void testGetRefsWithPrefixExcludingOverlappingPrefixes() throws IOExcepti checkContainsRef(refs, db.exactRef("HEAD")); } + @Test + public void testExternalUpdate_bug_102() throws Exception { + ((FileReftableDatabase) db.getRefDatabase()).setAutoRefresh(true); + assumeTrue(atLeastGitVersion(2, 45)); + Git git = Git.wrap(db); + git.tag().setName("foo").call(); + Ref ref = db.exactRef("refs/tags/foo"); + assertNotNull(ref); + runGitCommand("tag", "--force", "foo", "e"); + Ref e = db.exactRef("refs/heads/e"); + Ref foo = db.exactRef("refs/tags/foo"); + assertEquals(e.getObjectId(), foo.getObjectId()); + } + + private String toString(TemporaryBuffer b) throws IOException { + return RawParseUtils.decode(b.toByteArray()); + } + + private ExecutionResult runGitCommand(String... args) + throws IOException, InterruptedException { + FS fs = db.getFS(); + ProcessBuilder pb = fs.runInShell("git", args); + pb.directory(db.getWorkTree()); + System.err.println("PATH=" + pb.environment().get("PATH")); + ExecutionResult result = fs.execute(pb, null); + assertEquals(0, result.getRc()); + String err = toString(result.getStderr()); + if (!err.isEmpty()) { + System.err.println(err); + } + String out = toString(result.getStdout()); + if (!out.isEmpty()) { + System.out.println(out); + } + return result; + } + + private boolean atLeastGitVersion(int minMajor, int minMinor) + throws IOException, InterruptedException { + String version = toString(runGitCommand("version").getStdout()) + .split(" ")[2]; + System.out.println(version); + String[] digits = version.split("\\."); + int major = Integer.parseInt(digits[0]); + int minor = Integer.parseInt(digits[1]); + return (major >= minMajor) && (minor >= minMinor); + } + private RefUpdate updateRef(String name) throws IOException { final RefUpdate ref = db.updateRef(name); ref.setNewObjectId(db.resolve(Constants.HEAD));
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 6cad8b6..434f7e4 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
@@ -16,9 +16,9 @@ import java.io.File; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; import java.util.List; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; @@ -206,7 +206,7 @@ public void testDonePruneTooYoungPacks() throws Exception { // The old packfile is too young to be deleted. We should end up with // two pack files - gc.setExpire(new Date(oldPackfile.lastModified() - 1)); + gc.setExpire(Instant.ofEpochMilli(oldPackfile.lastModified() - 1)); gc.gc().get(); stats = gc.getStatistics(); assertEquals(0, stats.numberOfLooseObjects);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java new file mode 100644 index 0000000..cd1264e --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java
@@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024 Jacek Centkowski <geminica.programs@gmail.com> and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.stream.StreamSupport; + +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Test; + +public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { + @Test + public void testShouldReportZeroObjectsForInitializedRepo() + throws IOException { + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportAllPackFilesWhenNoGcWasPerformed() + throws Exception { + tr.packAndPrune(); + long result = gc.getStatistics().numberOfPackFilesSinceBitmap; + + assertEquals(repo.getObjectDatabase().getPacks().size(), result); + } + + @Test + public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception { + // given + addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + tr.packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & gc + parent = addCommit(parent); + gc.gc().get(); + assertEquals(2L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + tr.packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + private RevCommit addCommit(RevCommit parent) throws Exception { + PersonIdent ident = new PersonIdent("repo-metrics", "repo@metrics.com"); + TestRepository<FileRepository>.CommitBuilder builder = tr.commit() + .author(ident); + if (parent != null) { + builder.parent(parent); + } + RevCommit commit = builder.create(); + tr.update("master", commit); + parent = commit; + return parent; + } + + private long repositoryBitmapFiles() throws IOException { + return StreamSupport + .stream(Files + .newDirectoryStream(repo.getObjectDatabase() + .getPackDirectory().toPath(), "pack-*.bitmap") + .spliterator(), false) + .count(); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java index 8baa3cc..f84be21 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
@@ -19,7 +19,6 @@ import static org.junit.Assert.assertSame; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.BrokenBarrierException; @@ -31,6 +30,8 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.PackRefsCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; @@ -49,7 +50,7 @@ public void looseRefPacked() throws Exception { RevBlob a = tr.blob("a"); tr.lightweightTag("t", a); - gc.packRefs(); + packRefs(false); assertSame(repo.exactRef("refs/tags/t").getStorage(), Storage.PACKED); } @@ -58,9 +59,9 @@ public void emptyRefDirectoryDeleted() throws Exception { String ref = "dir/ref"; tr.branch(ref).commit().create(); String name = repo.findRef(ref).getName(); - Path dir = repo.getDirectory().toPath().resolve(name).getParent(); + Path dir = repo.getCommonDirectory().toPath().resolve(name).getParent(); assertNotNull(dir); - gc.packRefs(); + packRefs(true); assertFalse(Files.exists(dir)); } @@ -75,9 +76,9 @@ public void concurrentOnlyOneWritesPackedRefs() throws Exception { Callable<Integer> packRefs = () -> { syncPoint.await(); try { - gc.packRefs(); + packRefs(false); return 0; - } catch (IOException e) { + } catch (GitAPIException e) { return 1; } }; @@ -102,7 +103,7 @@ public void whileRefLockedRefNotPackedNoError() "refs/tags/t1")); try { refLock.lock(); - gc.packRefs(); + packRefs(false); } finally { refLock.unlock(); } @@ -145,7 +146,7 @@ public boolean isForceUpdate() { Future<Result> result2 = pool.submit(() -> { refUpdateLockedRef.await(); - gc.packRefs(); + packRefs(false); packRefsDone.await(); return null; }); @@ -173,19 +174,20 @@ public void dontPackHEAD_nonBare() throws Exception { assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); - gc.packRefs(); + PackRefsCommand packRefsCommand = git.packRefs().setAll(true); + packRefsCommand.call(); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); git.checkout().setName("refs/heads/side").call(); - gc.packRefs(); + packRefsCommand.call(); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); // check for detached HEAD git.checkout().setName(first.getName()).call(); - gc.packRefs(); + packRefsCommand.call(); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); } @@ -208,7 +210,7 @@ public void dontPackHEAD_bare() throws Exception { assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); assertNull(repo.exactRef("HEAD").getTarget().getObjectId()); - gc.packRefs(); + packRefs(true); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); assertEquals(repo.exactRef("HEAD").getTarget().getName(), "refs/heads/master"); @@ -216,9 +218,14 @@ public void dontPackHEAD_bare() throws Exception { // check for non-detached HEAD repo.updateRef(Constants.HEAD).link("refs/heads/side"); - gc.packRefs(); + packRefs(true); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE); assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(), second.getId()); } + + private void packRefs(boolean all) throws GitAPIException { + new PackRefsCommand(repo).setAll(all).call(); + } + }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java index ca0f684..84ec132 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java
@@ -16,8 +16,8 @@ import static org.junit.Assert.assertTrue; import java.io.File; +import java.time.Instant; import java.util.Collections; -import java.util.Date; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.lib.ObjectId; @@ -30,7 +30,7 @@ public class GcPruneNonReferencedTest extends GcTestCase { @Test public void nonReferencedNonExpiredObject_notPruned() throws Exception { RevBlob a = tr.blob("a"); - gc.setExpire(new Date(lastModified(a))); + gc.setExpire(Instant.ofEpochMilli(lastModified(a))); gc.prune(Collections.<ObjectId> emptySet()); assertTrue(repo.getObjectDatabase().has(a)); } @@ -58,7 +58,7 @@ public void nonReferencedExpiredObjectTree_pruned() throws Exception { @Test public void nonReferencedObjects_onlyExpiredPruned() throws Exception { RevBlob a = tr.blob("a"); - gc.setExpire(new Date(lastModified(a) + 1)); + gc.setExpire(Instant.ofEpochMilli(lastModified(a) + 1)); fsTick(); RevBlob b = tr.blob("b");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java index e6c1ee5..29f180d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
@@ -30,7 +30,7 @@ public void testPruneNone() throws Exception { 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(); - new File(repo.getDirectory(), Constants.LOGS + "/refs/heads/master") + new File(repo.getCommonDirectory(), Constants.LOGS + "/refs/heads/master") .delete(); stats = gc.getStatistics(); assertEquals(8, stats.numberOfLooseObjects);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java new file mode 100644 index 0000000..af52e2c --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java
@@ -0,0 +1,190 @@ +/* + * Copyright (c) 2024 Jacek Centkowski <geminica.programs@gmail.com> and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collection; +import java.util.stream.StreamSupport; + +import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.junit.Test; + +public class GcSinceBitmapStatisticsTest extends GcTestCase { + @Test + public void testShouldReportZeroPacksAndObjectsForInitializedRepo() + throws IOException { + RepoStatistics s = gc.getStatistics(); + assertEquals(0L, s.numberOfPackFilesSinceBitmap); + assertEquals(0L, s.numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportAllPackFilesWhenNoGcWasPerformed() + throws Exception { + tr.packAndPrune(); + long result = gc.getStatistics().numberOfPackFilesSinceBitmap; + + assertEquals(repo.getObjectDatabase().getPacks().size(), result); + } + + @Test + public void testShouldReportAllObjectsWhenNoGcWasPerformed() + throws Exception { + tr.packAndPrune(); + + assertEquals( + getNumberOfObjectsInPacks(repo.getObjectDatabase().getPacks()), + gc.getStatistics().numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportNoPacksFilesSinceBitmapWhenPackfilesAreOlderThanBitmapFile() + throws Exception { + addCommit(null); + configureGC(/* buildBitmap */ false).gc().get(); + assertEquals(1L, gc.getStatistics().numberOfPackFiles); + assertEquals(0L, repositoryBitmapFiles()); + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + + addCommit(null); + configureGC(/* buildBitmap */ true).gc().get(); + + assertEquals(1L, repositoryBitmapFiles()); + assertEquals(2L, gc.getStatistics().numberOfPackFiles); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception { + // given + addCommit(null); + assertEquals(2L, gc.getStatistics().numberOfObjectsSinceBitmap); + + gc.gc().get(); + assertEquals(0L, gc.getStatistics().numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportNewPacksSinceGcWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + assertEquals(1L, gc.getStatistics().numberOfPackFiles); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + + tr.packAndPrune(); + assertEquals(2L, gc.getStatistics().numberOfPackFiles); + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(0L, gc.getStatistics().numberOfLooseObjects); + assertEquals(0L, gc.getStatistics().numberOfObjectsSinceBitmap); + + // progress & pack + addCommit(parent); + assertEquals(1L, gc.getStatistics().numberOfLooseObjects); + assertEquals(1L, gc.getStatistics().numberOfObjectsSinceBitmap); + + tr.packAndPrune(); + assertEquals(0L, gc.getStatistics().numberOfLooseObjects); + // Number of objects contained in the newly created PackFile + assertEquals(3L, gc.getStatistics().numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportNewPacksFromTheLatestBitmapWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & gc + parent = addCommit(parent); + gc.gc().get(); + assertEquals(2L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + tr.packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + + // progress & gc + parent = addCommit(parent); + gc.gc().get(); + assertEquals(0L, gc.getStatistics().numberOfObjectsSinceBitmap); + + // progress & pack + addCommit(parent); + assertEquals(1L, gc.getStatistics().numberOfObjectsSinceBitmap); + + tr.packAndPrune(); + assertEquals(4L, gc.getStatistics().numberOfObjectsSinceBitmap); + } + + private RevCommit addCommit(RevCommit parent) throws Exception { + return tr.branch("master").commit() + .author(new PersonIdent("repo-metrics", "repo@metrics.com")) + .parent(parent).create(); + } + + private long repositoryBitmapFiles() throws IOException { + return StreamSupport + .stream(Files + .newDirectoryStream(repo.getObjectDatabase() + .getPackDirectory().toPath(), "pack-*.bitmap") + .spliterator(), false) + .count(); + } + + private long getNumberOfObjectsInPacks(Collection<Pack> packs) { + return packs.stream().mapToLong(pack -> { + try { + return pack.getObjectCount(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }).sum(); + } + + private GC configureGC(boolean buildBitmap) { + PackConfig pc = new PackConfig(repo.getObjectDatabase().getConfig()); + pc.setBuildBitmaps(buildBitmap); + gc.setPackConfig(pc); + return gc; + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java index 746a0a1..33cbc86 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
@@ -49,7 +49,10 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import java.io.File; @@ -66,6 +69,7 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -207,33 +211,35 @@ public void testOpenLooseObjectSuppressStaleFileHandleException() .fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b"); WindowCursor curs = new WindowCursor(db.getObjectDatabase()); - LooseObjects mock = mock(LooseObjects.class); + Config config = new Config(); + config.setString("core", null, "trustLooseObjectStat", "ALWAYS"); + LooseObjects spy = Mockito.spy(new LooseObjects(config, trash)); UnpackedObjectCache unpackedObjectCacheMock = mock( UnpackedObjectCache.class); - Mockito.when(mock.getObjectLoader(any(), any(), any())) - .thenThrow(new IOException("Stale File Handle")); - Mockito.when(mock.open(curs, id)).thenCallRealMethod(); - Mockito.when(mock.unpackedObjectCache()) - .thenReturn(unpackedObjectCacheMock); + doThrow(new IOException("Stale File Handle")).when(spy) + .getObjectLoader(any(), any(), any()); + doReturn(unpackedObjectCacheMock).when(spy).unpackedObjectCache(); - assertNull(mock.open(curs, id)); + assertNull(spy.open(curs, id)); verify(unpackedObjectCacheMock).remove(id); } - @Test + @Test(expected = IOException.class) public void testOpenLooseObjectPropagatesIOExceptions() throws Exception { ObjectId id = ObjectId .fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b"); WindowCursor curs = new WindowCursor(db.getObjectDatabase()); - LooseObjects mock = mock(LooseObjects.class); + Config config = new Config(); + config.setString("core", null, "trustLooseObjectStat", "NEVER"); + LooseObjects spy = spy(new LooseObjects(config, + db.getObjectDatabase().getDirectory())); - Mockito.when(mock.getObjectLoader(any(), any(), any())) - .thenThrow(new IOException("some IO failure")); - Mockito.when(mock.open(curs, id)).thenCallRealMethod(); + doThrow(new IOException("some IO failure")).when(spy) + .getObjectLoader(any(), any(), any()); - assertThrows(IOException.class, () -> mock.open(curs, id)); + spy.open(curs, id); } @Test @@ -243,17 +249,18 @@ public void testWindowCursorGetCommitGraph() throws Exception { db.getConfig().setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, ConfigConstants.CONFIG_KEY_WRITE_COMMIT_GRAPH, true); - WindowCursor curs = new WindowCursor(db.getObjectDatabase()); - assertTrue(curs.getCommitGraph().isEmpty()); - commitFile("file.txt", "content", "master"); - GC gc = new GC(db); - gc.gc().get(); - assertTrue(curs.getCommitGraph().isPresent()); + try (WindowCursor curs = new WindowCursor(db.getObjectDatabase())) { + assertTrue(curs.getCommitGraph().isEmpty()); + commitFile("file.txt", "content", "master"); + GC gc = new GC(db); + gc.gc().get(); + assertTrue(curs.getCommitGraph().isPresent()); - db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_COMMIT_GRAPH, false); + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_COMMIT_GRAPH, false); - assertTrue(curs.getCommitGraph().isEmpty()); + assertTrue(curs.getCommitGraph().isEmpty()); + } } @Test
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 24bdc4a..1f934ac 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
@@ -13,6 +13,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; @@ -25,6 +26,7 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; @@ -99,6 +101,39 @@ public void testIteratorMethodsContract() { } } + @Test + public void testIteratorMutableEntryCompareTo() { + Iterator<PackIndex.MutableEntry> iterA = smallIdx.iterator(); + Iterator<PackIndex.MutableEntry> iterB = smallIdx.iterator(); + + MutableEntry aEntry = iterA.next(); + iterB.next(); + MutableEntry bEntry = iterB.next(); + // b is one ahead + assertTrue(aEntry.compareBySha1To(bEntry) < 0); + assertTrue(bEntry.compareBySha1To(aEntry) > 0); + + // advance a, now should be equal + assertEquals(0, iterA.next().compareBySha1To(bEntry)); + } + + @Test + public void testIteratorMutableEntryCopyTo() { + Iterator<PackIndex.MutableEntry> it = smallIdx.iterator(); + + MutableObjectId firstOidCopy = new MutableObjectId(); + MutableEntry next = it.next(); + next.copyOidTo(firstOidCopy); + ObjectId firstImmutable = next.toObjectId(); + + MutableEntry second = it.next(); + + // The copy has the right value after "next" + assertTrue(firstImmutable.equals(firstOidCopy)); + assertFalse("iterator has moved", + second.toObjectId().equals(firstImmutable)); + } + /** * Test results of iterator comparing to content of well-known (prepared) * small index. @@ -106,22 +141,22 @@ public void testIteratorMethodsContract() { @Test public void testIteratorReturnedValues1() { Iterator<PackIndex.MutableEntry> iter = smallIdx.iterator(); - assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", iter.next() - .name()); - assertEquals("540a36d136cf413e4b064c2b0e0a4db60f77feab", iter.next() - .name()); - assertEquals("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259", iter.next() - .name()); - assertEquals("6ff87c4664981e4397625791c8ea3bbb5f2279a3", iter.next() - .name()); - assertEquals("82c6b885ff600be425b4ea96dee75dca255b69e7", iter.next() - .name()); - assertEquals("902d5476fa249b7abc9d84c611577a81381f0327", iter.next() - .name()); - assertEquals("aabf2ffaec9b497f0950352b3e582d73035c2035", iter.next() - .name()); - assertEquals("c59759f143fb1fe21c197981df75a7ee00290799", iter.next() - .name()); + assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", + iter.next().name()); + assertEquals("540a36d136cf413e4b064c2b0e0a4db60f77feab", + iter.next().name()); + assertEquals("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259", + iter.next().name()); + assertEquals("6ff87c4664981e4397625791c8ea3bbb5f2279a3", + iter.next().name()); + assertEquals("82c6b885ff600be425b4ea96dee75dca255b69e7", + iter.next().name()); + assertEquals("902d5476fa249b7abc9d84c611577a81381f0327", + iter.next().name()); + assertEquals("aabf2ffaec9b497f0950352b3e582d73035c2035", + iter.next().name()); + assertEquals("c59759f143fb1fe21c197981df75a7ee00290799", + iter.next().name()); assertFalse(iter.hasNext()); } @@ -198,16 +233,16 @@ public void testCompareEntriesOffsetsWithGetOffsets() { @Test public void testIteratorReturnedValues2() { Iterator<PackIndex.MutableEntry> iter = denseIdx.iterator(); - while (!iter.next().name().equals( - "0a3d7772488b6b106fb62813c4d6d627918d9181")) { + while (!iter.next().name() + .equals("0a3d7772488b6b106fb62813c4d6d627918d9181")) { // just iterating } - assertEquals("1004d0d7ac26fbf63050a234c9b88a46075719d3", iter.next() - .name()); // same level-1 - assertEquals("10da5895682013006950e7da534b705252b03be6", iter.next() - .name()); // same level-1 - assertEquals("1203b03dc816ccbb67773f28b3c19318654b0bc8", iter.next() - .name()); + assertEquals("1004d0d7ac26fbf63050a234c9b88a46075719d3", + iter.next().name()); // same level-1 + assertEquals("10da5895682013006950e7da534b705252b03be6", + iter.next().name()); // same level-1 + assertEquals("1203b03dc816ccbb67773f28b3c19318654b0bc8", + iter.next().name()); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java index 2bafde6..baa0182 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -90,25 +90,26 @@ public void refDirectorySetup() throws Exception { @Test public void testCreate() throws IOException { // setUp above created the directory. We just have to test it. - File d = diskRepo.getDirectory(); + File gitDir = diskRepo.getDirectory(); + File commonDir = diskRepo.getCommonDirectory(); assertSame(diskRepo, refdir.getRepository()); - assertTrue(new File(d, "refs").isDirectory()); - assertTrue(new File(d, "logs").isDirectory()); - assertTrue(new File(d, "logs/refs").isDirectory()); - assertFalse(new File(d, "packed-refs").exists()); + assertTrue(new File(commonDir, "refs").isDirectory()); + assertTrue(new File(commonDir, "logs").isDirectory()); + assertTrue(new File(commonDir, "logs/refs").isDirectory()); + assertFalse(new File(commonDir, "packed-refs").exists()); - assertTrue(new File(d, "refs/heads").isDirectory()); - assertTrue(new File(d, "refs/tags").isDirectory()); - assertEquals(2, new File(d, "refs").list().length); - assertEquals(0, new File(d, "refs/heads").list().length); - assertEquals(0, new File(d, "refs/tags").list().length); + assertTrue(new File(commonDir, "refs/heads").isDirectory()); + assertTrue(new File(commonDir, "refs/tags").isDirectory()); + assertEquals(2, new File(commonDir, "refs").list().length); + assertEquals(0, new File(commonDir, "refs/heads").list().length); + assertEquals(0, new File(commonDir, "refs/tags").list().length); - assertTrue(new File(d, "logs/refs/heads").isDirectory()); - assertFalse(new File(d, "logs/HEAD").exists()); - assertEquals(0, new File(d, "logs/refs/heads").list().length); + assertTrue(new File(commonDir, "logs/refs/heads").isDirectory()); + assertFalse(new File(gitDir, "logs/HEAD").exists()); + assertEquals(0, new File(commonDir, "logs/refs/heads").list().length); - assertEquals("ref: refs/heads/master\n", read(new File(d, HEAD))); + assertEquals("ref: refs/heads/master\n", read(new File(gitDir, HEAD))); } @Test(expected = UnsupportedOperationException.class) @@ -1382,7 +1383,7 @@ private void writeLooseRef(String name, String content) throws IOException { } private void deleteLooseRef(String name) { - File path = new File(diskRepo.getDirectory(), name); + File path = new File(diskRepo.getCommonDirectory(), name); assertTrue("deleted " + name, path.delete()); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java index cb977bd..acc36d7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
@@ -40,6 +40,7 @@ import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefRename; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate.Result; @@ -111,16 +112,17 @@ public void testNoCacheObjectIdSubclass() throws IOException { assertNotSame(newid, r.getObjectId()); assertSame(ObjectId.class, r.getObjectId().getClass()); assertEquals(newid, r.getObjectId()); - List<ReflogEntry> reverseEntries1 = db + List<ReflogEntry> reverseEntries1 = db.getRefDatabase() .getReflogReader("refs/heads/abc").getReverseEntries(); ReflogEntry entry1 = reverseEntries1.get(0); assertEquals(1, reverseEntries1.size()); assertEquals(ObjectId.zeroId(), entry1.getOldId()); assertEquals(r.getObjectId(), entry1.getNewId()); - assertEquals(new PersonIdent(db).toString(), entry1.getWho().toString()); + assertEquals(new PersonIdent(db).toString(), + entry1.getWho().toString()); assertEquals("", entry1.getComment()); - List<ReflogEntry> reverseEntries2 = db.getReflogReader("HEAD") - .getReverseEntries(); + List<ReflogEntry> reverseEntries2 = db.getRefDatabase() + .getReflogReader("HEAD").getReverseEntries(); assertEquals(0, reverseEntries2.size()); } @@ -136,8 +138,11 @@ public void testNewNamespaceConflictWithLoosePrefixNameExists() final RefUpdate ru2 = updateRef(newRef2); Result update2 = ru2.update(); assertEquals(Result.LOCK_FAILURE, update2); - assertEquals(1, db.getReflogReader("refs/heads/z").getReverseEntries().size()); - assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(1, refDb.getReflogReader("refs/heads/z") + .getReverseEntries().size()); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); } @Test @@ -147,8 +152,10 @@ public void testNewNamespaceConflictWithPackedPrefixNameExists() final RefUpdate ru = updateRef(newRef); Result update = ru.update(); assertEquals(Result.LOCK_FAILURE, update); - assertNull(db.getReflogReader("refs/heads/master/x")); - assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertNull(refDb.getReflogReader("refs/heads/master/x")); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); } @Test @@ -163,9 +170,12 @@ public void testNewNamespaceConflictWithLoosePrefixOfExisting() final RefUpdate ru2 = updateRef(newRef2); Result update2 = ru2.update(); assertEquals(Result.LOCK_FAILURE, update2); - assertEquals(1, db.getReflogReader("refs/heads/z/a").getReverseEntries().size()); - assertNull(db.getReflogReader("refs/heads/z")); - assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(1, refDb.getReflogReader("refs/heads/z/a") + .getReverseEntries().size()); + assertNull(refDb.getReflogReader("refs/heads/z")); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); } @Test @@ -175,8 +185,10 @@ public void testNewNamespaceConflictWithPackedPrefixOfExisting() final RefUpdate ru = updateRef(newRef); Result update = ru.update(); assertEquals(Result.LOCK_FAILURE, update); - assertNull(db.getReflogReader("refs/heads/prefix")); - assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertNull(refDb.getReflogReader("refs/heads/prefix")); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); } /** @@ -197,8 +209,11 @@ public void testDeleteHEADreferencedRef() throws IOException { Result delete = updateRef2.delete(); assertEquals(Result.REJECTED_CURRENT_BRANCH, delete); assertEquals(pid, db.resolve("refs/heads/master")); - assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size()); - assertEquals(0,db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(1, refDb.getReflogReader("refs/heads/master") + .getReverseEntries().size()); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); } @Test @@ -209,7 +224,8 @@ public void testWriteReflog() throws IOException { updateRef.setForceUpdate(true); Result update = updateRef.update(); assertEquals(Result.FORCED, update); - assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size()); + assertEquals(1, db.getRefDatabase().getReflogReader("refs/heads/master") + .getReverseEntries().size()); } @Test @@ -219,15 +235,18 @@ public void testLooseDelete() throws IOException { ref.update(); // create loose ref ref = updateRef(newRef); // refresh delete(ref, Result.NO_CHANGE); - assertNull(db.getReflogReader("refs/heads/abc")); + assertNull(db.getRefDatabase().getReflogReader("refs/heads/abc")); } @Test public void testDeleteHead() throws IOException { final RefUpdate ref = updateRef(Constants.HEAD); delete(ref, Result.REJECTED_CURRENT_BRANCH, true, false); - assertEquals(0, db.getReflogReader("refs/heads/master").getReverseEntries().size()); - assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(0, refDb.getReflogReader("refs/heads/master") + .getReverseEntries().size()); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); } @Test @@ -423,7 +442,7 @@ public void testUpdateRefDetached() throws Exception { // the branch HEAD referred to is left untouched assertEquals(pid, db.resolve("refs/heads/master")); - ReflogReader reflogReader = db.getReflogReader("HEAD"); + ReflogReader reflogReader = db.getRefDatabase().getReflogReader("HEAD"); ReflogEntry e = reflogReader.getReverseEntries().get(0); assertEquals(pid, e.getOldId()); assertEquals(ppid, e.getNewId()); @@ -453,7 +472,7 @@ public void testUpdateRefDetachedUnbornHead() throws Exception { // the branch HEAD referred to is left untouched assertNull(db.resolve("refs/heads/unborn")); - ReflogReader reflogReader = db.getReflogReader("HEAD"); + ReflogReader reflogReader = db.getRefDatabase().getReflogReader("HEAD"); ReflogEntry e = reflogReader.getReverseEntries().get(0); assertEquals(ObjectId.zeroId(), e.getOldId()); assertEquals(ppid, e.getNewId()); @@ -691,9 +710,12 @@ public void testRenameBranchNoPreviousLog() throws IOException { assertEquals(Result.RENAMED, result); assertEquals(rb, db.resolve("refs/heads/new/name")); assertNull(db.resolve("refs/heads/b")); - assertEquals(1, db.getReflogReader("new/name").getReverseEntries().size()); - assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name") - .getLastEntry().getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(1, refDb.getReflogReader("refs/heads/new/name") + .getReverseEntries().size()); + assertEquals("Branch: renamed b to new/name", + refDb.getReflogReader("refs/heads/new/name").getLastEntry() + .getComment()); assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists()); assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged } @@ -713,11 +735,15 @@ public void testRenameBranchHasPreviousLog() throws IOException { assertEquals(Result.RENAMED, result); assertEquals(rb, db.resolve("refs/heads/new/name")); assertNull(db.resolve("refs/heads/b")); - assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size()); - assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name") - .getLastEntry().getComment()); - assertEquals("Just a message", db.getReflogReader("new/name") - .getReverseEntries().get(1).getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(2, refDb.getReflogReader("refs/heads/new/name") + .getReverseEntries().size()); + assertEquals("Branch: renamed b to new/name", + refDb.getReflogReader("refs/heads/new/name").getLastEntry() + .getComment()); + assertEquals("Just a message", + refDb.getReflogReader("refs/heads/new/name").getReverseEntries() + .get(1).getComment()); assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists()); assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged } @@ -737,13 +763,20 @@ public void testRenameCurrentBranch() throws IOException { assertEquals(Result.RENAMED, result); assertEquals(rb, db.resolve("refs/heads/new/name")); assertNull(db.resolve("refs/heads/b")); - assertEquals("Branch: renamed b to new/name", db.getReflogReader( - "new/name").getLastEntry().getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals("Branch: renamed b to new/name", + refDb.getReflogReader("refs/heads/new/name").getLastEntry() + .getComment()); assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists()); assertEquals(rb, db.resolve(Constants.HEAD)); - assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size()); - assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name").getReverseEntries().get(0).getComment()); - assertEquals("Just a message", db.getReflogReader("new/name").getReverseEntries().get(1).getComment()); + assertEquals(2, refDb.getReflogReader("refs/heads/new/name") + .getReverseEntries().size()); + assertEquals("Branch: renamed b to new/name", + refDb.getReflogReader("refs/heads/new/name").getReverseEntries() + .get(0).getComment()); + assertEquals("Just a message", + refDb.getReflogReader("refs/heads/new/name").getReverseEntries() + .get(1).getComment()); } @Test @@ -766,11 +799,17 @@ public void testRenameBranchAlsoInPack() throws IOException { assertEquals(Result.RENAMED, result); assertEquals(rb2, db.resolve("refs/heads/new/name")); assertNull(db.resolve("refs/heads/b")); - assertEquals("Branch: renamed b to new/name", db.getReflogReader( - "new/name").getLastEntry().getComment()); - assertEquals(3, db.getReflogReader("refs/heads/new/name").getReverseEntries().size()); - assertEquals("Branch: renamed b to new/name", db.getReflogReader("refs/heads/new/name").getReverseEntries().get(0).getComment()); - assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals("Branch: renamed b to new/name", + refDb.getReflogReader("refs/heads/new/name").getLastEntry() + .getComment()); + assertEquals(3, refDb.getReflogReader("refs/heads/new/name") + .getReverseEntries().size()); + assertEquals("Branch: renamed b to new/name", + refDb.getReflogReader("refs/heads/new/name").getReverseEntries() + .get(0).getComment()); + assertEquals(0, + refDb.getReflogReader("HEAD").getReverseEntries().size()); // make sure b's log file is gone too. assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists()); @@ -789,9 +828,10 @@ public void tryRenameWhenLocked(String toLock, String fromName, ObjectId oldfromId = db.resolve(fromName); ObjectId oldHeadId = db.resolve(Constants.HEAD); writeReflog(db, oldfromId, "Just a message", fromName); - List<ReflogEntry> oldFromLog = db + RefDatabase refDb = db.getRefDatabase(); + List<ReflogEntry> oldFromLog = refDb .getReflogReader(fromName).getReverseEntries(); - List<ReflogEntry> oldHeadLog = oldHeadId != null ? db + List<ReflogEntry> oldHeadLog = oldHeadId != null ? refDb .getReflogReader(Constants.HEAD).getReverseEntries() : null; assertTrue("internal check, we have a log", new File(db.getDirectory(), @@ -818,10 +858,10 @@ public void tryRenameWhenLocked(String toLock, String fromName, assertEquals(oldHeadId, db.resolve(Constants.HEAD)); assertEquals(oldfromId, db.resolve(fromName)); assertNull(db.resolve(toName)); - assertEquals(oldFromLog.toString(), db.getReflogReader(fromName) + assertEquals(oldFromLog.toString(), refDb.getReflogReader(fromName) .getReverseEntries().toString()); if (oldHeadId != null && oldHeadLog != null) - assertEquals(oldHeadLog.toString(), db.getReflogReader( + assertEquals(oldHeadLog.toString(), refDb.getReflogReader( Constants.HEAD).getReverseEntries().toString()); } finally { lockFile.unlock(); @@ -942,15 +982,18 @@ public void testRenameRefNameColission1avoided() throws IOException { assertEquals(Result.RENAMED, result); assertNull(db.resolve("refs/heads/a")); assertEquals(rb, db.resolve("refs/heads/a/b")); - assertEquals(3, db.getReflogReader("a/b").getReverseEntries().size()); - assertEquals("Branch: renamed a to a/b", db.getReflogReader("a/b") - .getReverseEntries().get(0).getComment()); - assertEquals("Just a message", db.getReflogReader("a/b") + RefDatabase refDb = db.getRefDatabase(); + assertEquals(3, refDb.getReflogReader("refs/heads/a/b") + .getReverseEntries().size()); + assertEquals("Branch: renamed a to a/b", + refDb.getReflogReader("refs/heads/a/b").getReverseEntries() + .get(0).getComment()); + assertEquals("Just a message", refDb.getReflogReader("refs/heads/a/b") .getReverseEntries().get(1).getComment()); - assertEquals("Setup", db.getReflogReader("a/b").getReverseEntries() - .get(2).getComment()); + assertEquals("Setup", refDb.getReflogReader("refs/heads/a/b") + .getReverseEntries().get(2).getComment()); // same thing was logged to HEAD - assertEquals("Branch: renamed a to a/b", db.getReflogReader("HEAD") + assertEquals("Branch: renamed a to a/b", refDb.getReflogReader("HEAD") .getReverseEntries().get(0).getComment()); } @@ -978,15 +1021,20 @@ public void testRenameRefNameColission2avoided() throws IOException { assertNull(db.resolve("refs/heads/prefix/a")); assertEquals(rb, db.resolve("refs/heads/prefix")); - assertEquals(3, db.getReflogReader("prefix").getReverseEntries().size()); - assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader( - "prefix").getReverseEntries().get(0).getComment()); - assertEquals("Just a message", db.getReflogReader("prefix") - .getReverseEntries().get(1).getComment()); - assertEquals("Setup", db.getReflogReader("prefix").getReverseEntries() - .get(2).getComment()); - assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader( - "HEAD").getReverseEntries().get(0).getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(3, refDb.getReflogReader("refs/heads/prefix") + .getReverseEntries().size()); + assertEquals("Branch: renamed prefix/a to prefix", + refDb.getReflogReader("refs/heads/prefix").getReverseEntries() + .get(0).getComment()); + assertEquals("Just a message", + refDb.getReflogReader("refs/heads/prefix").getReverseEntries() + .get(1).getComment()); + assertEquals("Setup", refDb.getReflogReader("refs/heads/prefix") + .getReverseEntries().get(2).getComment()); + assertEquals("Branch: renamed prefix/a to prefix", + refDb.getReflogReader("HEAD").getReverseEntries().get(0) + .getComment()); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java index dc0e749..16645cb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
@@ -27,6 +27,7 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; @@ -154,18 +155,22 @@ public void testReadRightLog() throws Exception { setupReflog("logs/refs/heads/a", aLine); setupReflog("logs/refs/heads/master", masterLine); setupReflog("logs/HEAD", headLine); - assertEquals("branch: change to master", db.getReflogReader("master") - .getLastEntry().getComment()); - assertEquals("branch: change to a", db.getReflogReader("a") - .getLastEntry().getComment()); - assertEquals("branch: change to HEAD", db.getReflogReader("HEAD") - .getLastEntry().getComment()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals("branch: change to master", + refDb.getReflogReader("refs/heads/master").getLastEntry() + .getComment()); + assertEquals("branch: change to a", + refDb.getReflogReader("refs/heads/a").getLastEntry() + .getComment()); + assertEquals("branch: change to HEAD", + refDb.getReflogReader("HEAD").getLastEntry().getComment()); } @Test public void testReadLineWithMissingComment() throws Exception { setupReflog("logs/refs/heads/master", oneLineWithoutComment); - final ReflogReader reader = db.getReflogReader("master"); + final ReflogReader reader = db.getRefDatabase() + .getReflogReader("refs/heads/master"); ReflogEntry e = reader.getLastEntry(); assertEquals(ObjectId .fromString("da85355dfc525c9f6f3927b876f379f46ccf826e"), e @@ -183,15 +188,18 @@ public void testReadLineWithMissingComment() throws Exception { @Test public void testNoLog() throws Exception { - assertEquals(0, db.getReflogReader("master").getReverseEntries().size()); - assertNull(db.getReflogReader("master").getLastEntry()); + RefDatabase refDb = db.getRefDatabase(); + assertEquals(0, + refDb.getReflogReader("refs/heads/master").getReverseEntries() + .size()); + assertNull(refDb.getReflogReader("refs/heads/master").getLastEntry()); } @Test public void testCheckout() throws Exception { setupReflog("logs/HEAD", switchBranch); - List<ReflogEntry> entries = db.getReflogReader(Constants.HEAD) - .getReverseEntries(); + List<ReflogEntry> entries = db.getRefDatabase() + .getReflogReader(Constants.HEAD).getReverseEntries(); assertEquals(1, entries.size()); ReflogEntry entry = entries.get(0); CheckoutEntry checkout = entry.parseCheckout(); @@ -238,7 +246,7 @@ public void testSpecificEntryNumber() throws Exception { private void setupReflog(String logName, byte[] data) throws FileNotFoundException, IOException { - File logfile = new File(db.getDirectory(), logName); + File logfile = new File(db.getCommonDirectory(), logName); if (!logfile.getParentFile().mkdirs() && !logfile.getParentFile().isDirectory()) { throw new IOException(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java index 8d0e99d..a836333 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
@@ -16,6 +16,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; @@ -32,7 +34,7 @@ public void shouldFilterLineFeedFromMessage() throws Exception { ReflogWriter writer = new ReflogWriter((RefDirectory) db.getRefDatabase()); PersonIdent ident = new PersonIdent("John Doe", "john@doe.com", - 1243028200000L, 120); + Instant.ofEpochMilli(1243028200000L), ZoneOffset.ofHours(2)); ObjectId oldId = ObjectId .fromString("da85355dfc525c9f6f3927b876f379f46ccf826e"); ObjectId newId = ObjectId @@ -48,7 +50,7 @@ public void shouldFilterLineFeedFromMessage() throws Exception { private void readReflog(byte[] buffer) throws FileNotFoundException, IOException { - File logfile = new File(db.getDirectory(), "logs/refs/heads/master"); + File logfile = new File(db.getCommonDirectory(), "logs/refs/heads/master"); if (!logfile.getParentFile().mkdirs() && !logfile.getParentFile().isDirectory()) { throw new IOException(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java index 49e8a7b..e067beb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -28,6 +28,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.time.Instant; +import java.time.ZoneOffset; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -374,8 +375,10 @@ public void test008_FailOnWrongVersion() throws IOException { public void test009_CreateCommitOldFormat() throws IOException { final ObjectId treeId = insertTree(new TreeFormatter()); final CommitBuilder c = new CommitBuilder(); - c.setAuthor(new PersonIdent(author, 1154236443000L, -4 * 60)); - c.setCommitter(new PersonIdent(committer, 1154236443000L, -4 * 60)); + c.setAuthor(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); + c.setCommitter(new PersonIdent(committer, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); c.setMessage("A Commit\n"); c.setTreeId(treeId); assertEquals(treeId, c.getTreeId()); @@ -411,7 +414,8 @@ public void test020_createBlobTag() throws IOException { final TagBuilder t = new TagBuilder(); t.setObjectId(emptyId, Constants.OBJ_BLOB); t.setTag("test020"); - t.setTagger(new PersonIdent(author, 1154236443000L, -4 * 60)); + t.setTagger(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); t.setMessage("test020 tagged\n"); ObjectId actid = insertTag(t); assertEquals("6759556b09fbb4fd8ae5e315134481cc25d46954", actid.name()); @@ -419,8 +423,9 @@ public void test020_createBlobTag() throws IOException { RevTag mapTag = parseTag(actid); assertEquals(Constants.OBJ_BLOB, mapTag.getObject().getType()); assertEquals("test020 tagged\n", mapTag.getFullMessage()); - assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag - .getTaggerIdent()); + assertEquals(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4)), + mapTag.getTaggerIdent()); assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag .getObject().getId().name()); } @@ -434,7 +439,8 @@ public void test021_createTreeTag() throws IOException { final TagBuilder t = new TagBuilder(); t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE); t.setTag("test021"); - t.setTagger(new PersonIdent(author, 1154236443000L, -4 * 60)); + t.setTagger(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); t.setMessage("test021 tagged\n"); ObjectId actid = insertTag(t); assertEquals("b0517bc8dbe2096b419d42424cd7030733f4abe5", actid.name()); @@ -442,8 +448,9 @@ public void test021_createTreeTag() throws IOException { RevTag mapTag = parseTag(actid); assertEquals(Constants.OBJ_TREE, mapTag.getObject().getType()); assertEquals("test021 tagged\n", mapTag.getFullMessage()); - assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag - .getTaggerIdent()); + assertEquals(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4)), + mapTag.getTaggerIdent()); assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag .getObject().getId().name()); } @@ -455,17 +462,18 @@ public void test022_createCommitTag() throws IOException { almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final CommitBuilder almostEmptyCommit = new CommitBuilder(); - almostEmptyCommit.setAuthor(new PersonIdent(author, 1154236443000L, - -2 * 60)); // not exactly the same - almostEmptyCommit.setCommitter(new PersonIdent(author, 1154236443000L, - -2 * 60)); + almostEmptyCommit.setAuthor(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-2))); + almostEmptyCommit.setCommitter(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-2))); almostEmptyCommit.setMessage("test022\n"); almostEmptyCommit.setTreeId(almostEmptyTreeId); ObjectId almostEmptyCommitId = insertCommit(almostEmptyCommit); final TagBuilder t = new TagBuilder(); t.setObjectId(almostEmptyCommitId, Constants.OBJ_COMMIT); t.setTag("test022"); - t.setTagger(new PersonIdent(author, 1154236443000L, -4 * 60)); + t.setTagger(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); t.setMessage("test022 tagged\n"); ObjectId actid = insertTag(t); assertEquals("0ce2ebdb36076ef0b38adbe077a07d43b43e3807", actid.name()); @@ -473,8 +481,9 @@ public void test022_createCommitTag() throws IOException { RevTag mapTag = parseTag(actid); assertEquals(Constants.OBJ_COMMIT, mapTag.getObject().getType()); assertEquals("test022 tagged\n", mapTag.getFullMessage()); - assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag - .getTaggerIdent()); + assertEquals(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4)), + mapTag.getTaggerIdent()); assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag .getObject().getId().name()); } @@ -488,9 +497,9 @@ public void test023_createCommitNonAnullii() throws IOException { CommitBuilder commit = new CommitBuilder(); commit.setTreeId(almostEmptyTreeId); commit.setAuthor(new PersonIdent("Joe H\u00e4cker", "joe@example.com", - 4294967295000L, 60)); + Instant.ofEpochMilli(4294967295000L), ZoneOffset.ofHours(1))); commit.setCommitter(new PersonIdent("Joe Hacker", "joe2@example.com", - 4294967295000L, 60)); + Instant.ofEpochMilli(4294967295000L), ZoneOffset.ofHours(1))); commit.setEncoding(UTF_8); commit.setMessage("\u00dcbergeeks"); ObjectId cid = insertCommit(commit); @@ -509,9 +518,9 @@ public void test024_createCommitNonAscii() throws IOException { CommitBuilder commit = new CommitBuilder(); commit.setTreeId(almostEmptyTreeId); commit.setAuthor(new PersonIdent("Joe H\u00e4cker", "joe@example.com", - 4294967295000L, 60)); + Instant.ofEpochMilli(4294967295000L), ZoneOffset.ofHours(1))); commit.setCommitter(new PersonIdent("Joe Hacker", "joe2@example.com", - 4294967295000L, 60)); + Instant.ofEpochMilli(4294967295000L), ZoneOffset.ofHours(1))); commit.setEncoding(ISO_8859_1); commit.setMessage("\u00dcbergeeks"); ObjectId cid = insertCommit(commit); @@ -544,8 +553,10 @@ public void test026_CreateCommitMultipleparents() throws IOException { .fromString("00b1f73724f493096d1ffa0b0f1f1482dbb8c936"), treeId); final CommitBuilder c1 = new CommitBuilder(); - c1.setAuthor(new PersonIdent(author, 1154236443000L, -4 * 60)); - c1.setCommitter(new PersonIdent(committer, 1154236443000L, -4 * 60)); + c1.setAuthor(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); + c1.setCommitter(new PersonIdent(committer, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); c1.setMessage("A Commit\n"); c1.setTreeId(treeId); assertEquals(treeId, c1.getTreeId()); @@ -555,8 +566,10 @@ public void test026_CreateCommitMultipleparents() throws IOException { assertEquals(cmtid1, actid1); final CommitBuilder c2 = new CommitBuilder(); - c2.setAuthor(new PersonIdent(author, 1154236443000L, -4 * 60)); - c2.setCommitter(new PersonIdent(committer, 1154236443000L, -4 * 60)); + c2.setAuthor(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); + c2.setCommitter(new PersonIdent(committer, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); c2.setMessage("A Commit 2\n"); c2.setTreeId(treeId); assertEquals(treeId, c2.getTreeId()); @@ -577,8 +590,10 @@ public void test026_CreateCommitMultipleparents() throws IOException { assertEquals(actid1, rm2.getParent(0)); final CommitBuilder c3 = new CommitBuilder(); - c3.setAuthor(new PersonIdent(author, 1154236443000L, -4 * 60)); - c3.setCommitter(new PersonIdent(committer, 1154236443000L, -4 * 60)); + c3.setAuthor(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); + c3.setCommitter(new PersonIdent(committer, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); c3.setMessage("A Commit 3\n"); c3.setTreeId(treeId); assertEquals(treeId, c3.getTreeId()); @@ -600,8 +615,10 @@ public void test026_CreateCommitMultipleparents() throws IOException { assertEquals(actid2, rm3.getParent(1)); final CommitBuilder c4 = new CommitBuilder(); - c4.setAuthor(new PersonIdent(author, 1154236443000L, -4 * 60)); - c4.setCommitter(new PersonIdent(committer, 1154236443000L, -4 * 60)); + c4.setAuthor(new PersonIdent(author, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); + c4.setCommitter(new PersonIdent(committer, + Instant.ofEpochMilli(1154236443000L), ZoneOffset.ofHours(-4))); c4.setMessage("A Commit 4\n"); c4.setTreeId(treeId); assertEquals(treeId, c3.getTreeId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java new file mode 100644 index 0000000..82f3eb1 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
@@ -0,0 +1,161 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_LARGEOFFSETS; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OBJECTOFFSETS; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDFANOUT; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDLOOKUP; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_PACKNAMES; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_REVINDEX; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.junit.FakeIndexFactory; +import org.eclipse.jgit.junit.FakeIndexFactory.IndexObject; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.util.NB; +import org.junit.Test; + +public class MultiPackIndexWriterTest { + + @Test + public void write_allSmallOffsets() throws IOException { + PackIndex index1 = indexOf( + object("0000000000000000000000000000000000000001", 500), + object("0000000000000000000000000000000000000003", 1500), + object("0000000000000000000000000000000000000005", 3000)); + PackIndex index2 = indexOf( + object("0000000000000000000000000000000000000002", 500), + object("0000000000000000000000000000000000000004", 1500), + object("0000000000000000000000000000000000000006", 3000)); + + Map<String, PackIndex> data = Map.of("packname1", index1, "packname2", + index2); + + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, data); + // header (12 bytes) + // + chunkHeader (6 * 12 bytes) + // + fanout table (256 * 4 bytes) + // + OIDs (6 * 20 bytes) + // + (pack, offset) pairs (6 * 8) + // + RIDX (6 * 4 bytes) + // + packfile names (2 * 10) + // + checksum (20) + assertEquals(1340, out.size()); + List<Integer> chunkIds = readChunkIds(out); + assertEquals(5, chunkIds.size()); + assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT)); + assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP)); + assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS)); + assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX)); + assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES)); + } + + @Test + public void write_smallOffset_limit() throws IOException { + PackIndex index1 = indexOf( + object("0000000000000000000000000000000000000001", 500), + object("0000000000000000000000000000000000000003", 1500), + object("0000000000000000000000000000000000000005", (1L << 32) -1)); + PackIndex index2 = indexOf( + object("0000000000000000000000000000000000000002", 500), + object("0000000000000000000000000000000000000004", 1500), + object("0000000000000000000000000000000000000006", 3000)); + Map<String, PackIndex> data = + Map.of("packname1", index1, "packname2", index2); + + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, data); + // header (12 bytes) + // + chunkHeader (6 * 12 bytes) + // + fanout table (256 * 4 bytes) + // + OIDs (6 * 20 bytes) + // + (pack, offset) pairs (6 * 8) + // + RIDX (6 * 4 bytes) + // + packfile names (2 * 10) + // + checksum (20) + assertEquals(1340, out.size()); + List<Integer> chunkIds = readChunkIds(out); + assertEquals(5, chunkIds.size()); + assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT)); + assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP)); + assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS)); + assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX)); + assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES)); + } + + @Test + public void write_largeOffset() throws IOException { + PackIndex index1 = indexOf( + object("0000000000000000000000000000000000000001", 500), + object("0000000000000000000000000000000000000003", 1500), + object("0000000000000000000000000000000000000005", 1L << 32)); + PackIndex index2 = indexOf( + object("0000000000000000000000000000000000000002", 500), + object("0000000000000000000000000000000000000004", 1500), + object("0000000000000000000000000000000000000006", 3000)); + Map<String, PackIndex> data = + Map.of("packname1", index1, "packname2", index2); + + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, data); + // header (12 bytes) + // + chunkHeader (7 * 12 bytes) + // + fanout table (256 * 4 bytes) + // + OIDs (6 * 20 bytes) + // + (pack, offset) pairs (6 * 8) + // + (large-offset) (1 * 8) + // + RIDX (6 * 4 bytes) + // + packfile names (2 * 10) + // + checksum (20) + assertEquals(1360, out.size()); + List<Integer> chunkIds = readChunkIds(out); + assertEquals(6, chunkIds.size()); + assertEquals(0, chunkIds.indexOf(MIDX_CHUNKID_OIDFANOUT)); + assertEquals(1, chunkIds.indexOf(MIDX_CHUNKID_OIDLOOKUP)); + assertEquals(2, chunkIds.indexOf(MIDX_CHUNKID_OBJECTOFFSETS)); + assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_LARGEOFFSETS)); + assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX)); + assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES)); + } + + private List<Integer> readChunkIds(ByteArrayOutputStream out) { + List<Integer> chunkIds = new ArrayList<>(); + byte[] raw = out.toByteArray(); + int numChunks = raw[6]; + int position = 12; + for (int i = 0; i < numChunks; i++) { + chunkIds.add(NB.decodeInt32(raw, position)); + position += CHUNK_LOOKUP_WIDTH; + } + return chunkIds; + } + + private static PackIndex indexOf(IndexObject... objs) { + return FakeIndexFactory.indexOf(Arrays.asList(objs)); + } + + private static IndexObject object(String name, long offset) { + return new IndexObject(name, offset); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java new file mode 100644 index 0000000..1d8bde0 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java
@@ -0,0 +1,239 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.junit.FakeIndexFactory; +import org.eclipse.jgit.junit.FakeIndexFactory.IndexObject; +import org.junit.Test; + +public class PackIndexMergerTest { + + @Test + public void rawIterator_noDuplicates() { + PackIndex idxOne = indexOf( + oidOffset("0000000000000000000000000000000000000001", 500), + oidOffset("0000000000000000000000000000000000000005", 12), + oidOffset("0000000000000000000000000000000000000010", 1500)); + PackIndex idxTwo = indexOf( + oidOffset("0000000000000000000000000000000000000002", 501), + oidOffset("0000000000000000000000000000000000000003", 13), + oidOffset("0000000000000000000000000000000000000015", 1501)); + PackIndex idxThree = indexOf( + oidOffset("0000000000000000000000000000000000000004", 502), + oidOffset("0000000000000000000000000000000000000007", 14), + oidOffset("0000000000000000000000000000000000000012", 1502)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + assertEquals(9, merger.getUniqueObjectCount()); + assertEquals(3, merger.getPackCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + Iterator<PackIndexMerger.MidxMutableEntry> it = merger.rawIterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 0, 500); + assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 501); + assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 13); + assertNextEntry(it, "0000000000000000000000000000000000000004", 2, 502); + assertNextEntry(it, "0000000000000000000000000000000000000005", 0, 12); + assertNextEntry(it, "0000000000000000000000000000000000000007", 2, 14); + assertNextEntry(it, "0000000000000000000000000000000000000010", 0, + 1500); + assertNextEntry(it, "0000000000000000000000000000000000000012", 2, + 1502); + assertNextEntry(it, "0000000000000000000000000000000000000015", 1, + 1501); + assertFalse(it.hasNext()); + } + + @Test + public void rawIterator_allDuplicates() { + PackIndex idxOne = indexOf( + oidOffset("0000000000000000000000000000000000000001", 500), + oidOffset("0000000000000000000000000000000000000005", 12), + oidOffset("0000000000000000000000000000000000000010", 1500)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idxOne, "p2", idxOne, "p3", idxOne)); + assertEquals(3, merger.getUniqueObjectCount()); + assertEquals(3, merger.getPackCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + Iterator<PackIndexMerger.MidxMutableEntry> it = merger.rawIterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 0, 500); + assertNextEntry(it, "0000000000000000000000000000000000000001", 1, 500); + assertNextEntry(it, "0000000000000000000000000000000000000001", 2, 500); + assertNextEntry(it, "0000000000000000000000000000000000000005", 0, 12); + assertNextEntry(it, "0000000000000000000000000000000000000005", 1, 12); + assertNextEntry(it, "0000000000000000000000000000000000000005", 2, 12); + assertNextEntry(it, "0000000000000000000000000000000000000010", 0, + 1500); + assertNextEntry(it, "0000000000000000000000000000000000000010", 1, + 1500); + assertNextEntry(it, "0000000000000000000000000000000000000010", 2, + 1500); + assertFalse(it.hasNext()); + } + + @Test + public void bySha1Iterator_noDuplicates() { + PackIndex idxOne = indexOf( + oidOffset("0000000000000000000000000000000000000001", 500), + oidOffset("0000000000000000000000000000000000000005", 12), + oidOffset("0000000000000000000000000000000000000010", 1500)); + PackIndex idxTwo = indexOf( + oidOffset("0000000000000000000000000000000000000002", 501), + oidOffset("0000000000000000000000000000000000000003", 13), + oidOffset("0000000000000000000000000000000000000015", 1501)); + PackIndex idxThree = indexOf( + oidOffset("0000000000000000000000000000000000000004", 502), + oidOffset("0000000000000000000000000000000000000007", 14), + oidOffset("0000000000000000000000000000000000000012", 1502)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + assertEquals(9, merger.getUniqueObjectCount()); + assertEquals(3, merger.getPackCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + Iterator<PackIndexMerger.MidxMutableEntry> it = merger.bySha1Iterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 0, 500); + assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 501); + assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 13); + assertNextEntry(it, "0000000000000000000000000000000000000004", 2, 502); + assertNextEntry(it, "0000000000000000000000000000000000000005", 0, 12); + assertNextEntry(it, "0000000000000000000000000000000000000007", 2, 14); + assertNextEntry(it, "0000000000000000000000000000000000000010", 0, + 1500); + assertNextEntry(it, "0000000000000000000000000000000000000012", 2, + 1502); + assertNextEntry(it, "0000000000000000000000000000000000000015", 1, + 1501); + assertFalse(it.hasNext()); + } + + @Test + public void bySha1Iterator_allDuplicates() { + PackIndex idxOne = indexOf( + oidOffset("0000000000000000000000000000000000000001", 500), + oidOffset("0000000000000000000000000000000000000005", 12), + oidOffset("0000000000000000000000000000000000000010", 1500)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idxOne, "p2", idxOne, "p3", idxOne)); + assertEquals(3, merger.getUniqueObjectCount()); + assertEquals(3, merger.getPackCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + Iterator<PackIndexMerger.MidxMutableEntry> it = merger.bySha1Iterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 0, 500); + assertNextEntry(it, "0000000000000000000000000000000000000005", 0, 12); + assertNextEntry(it, "0000000000000000000000000000000000000010", 0, + 1500); + assertFalse(it.hasNext()); + } + + @Test + public void bySha1Iterator_differentIndexSizes() { + PackIndex idxOne = indexOf( + oidOffset("0000000000000000000000000000000000000010", 1500)); + PackIndex idxTwo = indexOf( + oidOffset("0000000000000000000000000000000000000002", 500), + oidOffset("0000000000000000000000000000000000000003", 12)); + PackIndex idxThree = indexOf( + oidOffset("0000000000000000000000000000000000000004", 500), + oidOffset("0000000000000000000000000000000000000007", 12), + oidOffset("0000000000000000000000000000000000000012", 1500)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + assertEquals(6, merger.getUniqueObjectCount()); + assertEquals(3, merger.getPackCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + Iterator<PackIndexMerger.MidxMutableEntry> it = merger.bySha1Iterator(); + assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 500); + assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 12); + assertNextEntry(it, "0000000000000000000000000000000000000004", 2, 500); + assertNextEntry(it, "0000000000000000000000000000000000000007", 2, 12); + assertNextEntry(it, "0000000000000000000000000000000000000010", 0, + 1500); + assertNextEntry(it, "0000000000000000000000000000000000000012", 2, + 1500); + assertFalse(it.hasNext()); + } + + @Test + public void merger_noIndexes() { + PackIndexMerger merger = new PackIndexMerger(Map.of()); + assertEquals(0, merger.getUniqueObjectCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + assertTrue(merger.getPackNames().isEmpty()); + assertEquals(0, merger.getPackCount()); + assertFalse(merger.bySha1Iterator().hasNext()); + } + + @Test + public void merger_emptyIndexes() { + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", indexOf(), "p2", indexOf())); + assertEquals(0, merger.getUniqueObjectCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + assertEquals(2, merger.getPackNames().size()); + assertEquals(2, merger.getPackCount()); + assertFalse(merger.bySha1Iterator().hasNext()); + } + + @Test + public void bySha1Iterator_largeOffsets_needsChunk() { + PackIndex idx1 = indexOf( + oidOffset("0000000000000000000000000000000000000002", 1L << 32), + oidOffset("0000000000000000000000000000000000000004", 12)); + PackIndex idx2 = indexOf(oidOffset( + "0000000000000000000000000000000000000003", (1L << 31) + 10)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idx1, "p2", idx2)); + assertTrue(merger.needsLargeOffsetsChunk()); + assertEquals(2, merger.getOffsetsOver31BitsCount()); + assertEquals(3, merger.getUniqueObjectCount()); + } + + @Test + public void bySha1Iterator_largeOffsets_noChunk() { + // If no value is over 2^32-1, then we don't need large offset + PackIndex idx1 = indexOf( + oidOffset("0000000000000000000000000000000000000002", + (1L << 31) + 15), + oidOffset("0000000000000000000000000000000000000004", 12)); + PackIndex idx2 = indexOf(oidOffset( + "0000000000000000000000000000000000000003", (1L << 31) + 10)); + PackIndexMerger merger = new PackIndexMerger( + Map.of("p1", idx1, "p2", idx2)); + assertFalse(merger.needsLargeOffsetsChunk()); + assertEquals(2, merger.getOffsetsOver31BitsCount()); + assertEquals(3, merger.getUniqueObjectCount()); + } + + private static void assertNextEntry( + Iterator<PackIndexMerger.MidxMutableEntry> it, String oid, + int packId, long offset) { + assertTrue(it.hasNext()); + PackIndexMerger.MidxMutableEntry e = it.next(); + assertEquals(oid, e.getObjectId().name()); + assertEquals(packId, e.getPackId()); + assertEquals(offset, e.getOffset()); + } + + private static IndexObject oidOffset(String oid, long offset) { + return new IndexObject(oid, offset); + } + + private static PackIndex indexOf(IndexObject... objs) { + return FakeIndexFactory.indexOf(Arrays.asList(objs)); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexPeekIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexPeekIteratorTest.java new file mode 100644 index 0000000..917288a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexPeekIteratorTest.java
@@ -0,0 +1,71 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Arrays; + +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.junit.FakeIndexFactory; +import org.junit.Test; + +public class PackIndexPeekIteratorTest { + @Test + public void next() { + PackIndex index1 = indexOf( + object("0000000000000000000000000000000000000001", 500), + object("0000000000000000000000000000000000000003", 1500), + object("0000000000000000000000000000000000000005", 3000)); + PackIndexMerger.PackIndexPeekIterator it = new PackIndexMerger.PackIndexPeekIterator(0, index1); + assertEquals("0000000000000000000000000000000000000001", it.next().name()); + assertEquals("0000000000000000000000000000000000000003", it.next().name()); + assertEquals("0000000000000000000000000000000000000005", it.next().name()); + assertNull(it.next()); + } + + @Test + public void peek_doesNotAdvance() { + PackIndex index1 = indexOf( + object("0000000000000000000000000000000000000001", 500), + object("0000000000000000000000000000000000000003", 1500), + object("0000000000000000000000000000000000000005", 3000)); + PackIndexMerger.PackIndexPeekIterator it = new PackIndexMerger.PackIndexPeekIterator(0, index1); + it.next(); + assertEquals("0000000000000000000000000000000000000001", it.peek().name()); + assertEquals("0000000000000000000000000000000000000001", it.peek().name()); + it.next(); + assertEquals("0000000000000000000000000000000000000003", it.peek().name()); + assertEquals("0000000000000000000000000000000000000003", it.peek().name()); + it.next(); + assertEquals("0000000000000000000000000000000000000005", it.peek().name()); + assertEquals("0000000000000000000000000000000000000005", it.peek().name()); + it.next(); + assertNull(it.peek()); + assertNull(it.peek()); + } + + @Test + public void empty() { + PackIndex index1 = indexOf(); + PackIndexMerger.PackIndexPeekIterator it = new PackIndexMerger.PackIndexPeekIterator(0, index1); + assertNull(it.next()); + assertNull(it.peek()); + } + + private static PackIndex indexOf(FakeIndexFactory.IndexObject... objs) { + return FakeIndexFactory.indexOf(Arrays.asList(objs)); + } + + private static FakeIndexFactory.IndexObject object(String name, long offset) { + return new FakeIndexFactory.IndexObject(name, offset); + } +} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java index ea0d92a..a54002b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java
@@ -29,6 +29,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -175,7 +177,8 @@ public void hasObjMapRefsSmallTable() throws IOException { @Test public void hasObjLogs() throws IOException { - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); String msg = "test"; ReftableConfig cfg = new ReftableConfig(); cfg.setIndexObjects(false); @@ -617,7 +620,8 @@ public void invalidReflogWriteOrderUpdateIndex() throws IOException { .setMinUpdateIndex(1) .setMaxUpdateIndex(2) .begin(); - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); String msg = "test"; writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg); @@ -633,7 +637,8 @@ public void invalidReflogWriteOrderName() throws IOException { .setMinUpdateIndex(1) .setMaxUpdateIndex(1) .begin(); - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); String msg = "test"; writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(1), msg); @@ -647,7 +652,8 @@ public void invalidReflogWriteOrderName() throws IOException { public void withReflog() throws IOException { Ref master = ref(MASTER, 1); Ref next = ref(NEXT, 2); - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); String msg = "test"; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -712,11 +718,14 @@ public void reflogReader() throws IOException { writer.writeRef(master); writer.writeRef(next); - PersonIdent who1 = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who1 = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); writer.writeLog(MASTER, 3, who1, ObjectId.zeroId(), id(1), "1"); - PersonIdent who2 = new PersonIdent("Log", "Ger", 1500079710, -8 * 60); + PersonIdent who2 = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); writer.writeLog(MASTER, 2, who2, id(1), id(2), "2"); - PersonIdent who3 = new PersonIdent("Log", "Ger", 1500079711, -8 * 60); + PersonIdent who3 = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); writer.writeLog(MASTER, 1, who3, id(2), id(3), "3"); writer.finish(); @@ -753,7 +762,8 @@ public void allRefs() throws IOException { .setMaxUpdateIndex(1) .setConfig(cfg) .begin(); - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); // Fill out the 1st ref block. List<String> names = new ArrayList<>(); @@ -782,7 +792,8 @@ public void allRefs() throws IOException { @Test public void reflogSeek() throws IOException { - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochSecond(1500079709), ZoneOffset.ofHours(-8)); String msg = "test"; String msgNext = "test next"; @@ -827,7 +838,8 @@ public void reflogSeek() throws IOException { @Test public void reflogSeekPrefix() throws IOException { - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ReftableWriter writer = new ReftableWriter(buffer) @@ -850,7 +862,8 @@ public void reflogSeekPrefix() throws IOException { @Test public void onlyReflog() throws IOException { - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); String msg = "test"; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -916,7 +929,8 @@ public void logScan() throws IOException { writer.writeRef(ref); } - PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + PersonIdent who = new PersonIdent("Log", "Ger", + Instant.ofEpochMilli(1500079709), ZoneOffset.ofHours(-8)); for (Ref ref : refs) { writer.writeLog(ref.getName(), 1, who, ObjectId.zeroId(), ref.getObjectId(),
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java index 450b753..1581d49 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
@@ -11,6 +11,7 @@ package org.eclipse.jgit.junit; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.time.Instant.EPOCH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -18,7 +19,6 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import java.util.Date; import java.util.regex.Pattern; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; @@ -199,8 +199,8 @@ public void amendRef() throws Exception { assertEquals(orig.getAuthorIdent(), amended.getAuthorIdent()); // Committer name/email is the same, but time was incremented. - assertEquals(new PersonIdent(orig.getCommitterIdent(), new Date(0)), - new PersonIdent(amended.getCommitterIdent(), new Date(0))); + assertEquals(new PersonIdent(orig.getCommitterIdent(), EPOCH), + new PersonIdent(amended.getCommitterIdent(), EPOCH)); assertTrue(orig.getCommitTime() < amended.getCommitTime()); assertEquals("foo contents", blobAsString(amended, "foo")); @@ -275,9 +275,9 @@ public void cherryPick() throws Exception { RevCommit toPick = tr.commit() .parent(tr.commit().create()) // Can't cherry-pick root. .author(new PersonIdent("Cherrypick Author", "cpa@example.com", - tr.getDate(), tr.getTimeZone())) + tr.getInstant(), tr.getTimeZoneId())) .author(new PersonIdent("Cherrypick Committer", "cpc@example.com", - tr.getDate(), tr.getTimeZone())) + tr.getInstant(), tr.getTimeZoneId())) .message("message to cherry-pick") .add("bar", "bar contents\n") .create(); @@ -294,8 +294,8 @@ public void cherryPick() throws Exception { assertEquals(toPick.getAuthorIdent(), result.getAuthorIdent()); // Committer name/email matches default, and time was incremented. - assertEquals(new PersonIdent(head.getCommitterIdent(), new Date(0)), - new PersonIdent(result.getCommitterIdent(), new Date(0))); + assertEquals(new PersonIdent(head.getCommitterIdent(), EPOCH), + new PersonIdent(result.getCommitterIdent(), EPOCH)); assertTrue(toPick.getCommitTime() < result.getCommitTime()); assertEquals("message to cherry-pick", result.getFullMessage());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java index 31940a1..06fee8e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
@@ -1636,6 +1636,47 @@ public void testCoreCommitGraphConfig() { assertFalse(config.get(CoreConfig.KEY).enableCommitGraph()); } + @Test + public void testGetNoDefaultBoolean() { + Config config = new Config(); + assertNull(config.getBoolean("foo", "bar")); + assertNull(config.getBoolean("foo", "bar", "baz")); + } + + @Test + public void testGetNoDefaultEnum() { + Config config = new Config(); + assertNull(config.getEnum(new TestEnum[] { TestEnum.ONE_TWO }, "foo", + "bar", "baz")); + } + + @Test + public void testGetNoDefaultInt() { + Config config = new Config(); + assertNull(config.getInt("foo", "bar")); + assertNull(config.getInt("foo", "bar", "baz")); + } + @Test + public void testGetNoDefaultIntInRange() { + Config config = new Config(); + assertNull(config.getIntInRange("foo", "bar", 1, 5)); + assertNull(config.getIntInRange("foo", "bar", "baz", 1, 5)); + } + + @Test + public void testGetNoDefaultLong() { + Config config = new Config(); + assertNull(config.getLong("foo", "bar")); + assertNull(config.getLong("foo", "bar", "baz")); + } + + @Test + public void testGetNoDefaultTimeUnit() { + Config config = new Config(); + assertNull(config.getTimeUnit("foo", "bar", "baz", + TimeUnit.SECONDS)); + } + private static void assertValueRoundTrip(String value) throws ConfigInvalidException { assertValueRoundTrip(value, value);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java index 32f6766..5c2b190 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java
@@ -96,6 +96,16 @@ public void testGetKeyFormat_x509() throws Exception { } @Test + public void testGetKeyFormat_ssh() throws Exception { + Config c = parse("" // + + "[gpg]\n" // + + " format = ssh\n" // + ); + + assertEquals(GpgConfig.GpgFormat.SSH, new GpgConfig(c).getKeyFormat()); + } + + @Test public void testGetSigningKey() throws Exception { Config c = parse("" // + "[user]\n" //
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java index 2b7b6ca..cd98606 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -2,7 +2,7 @@ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> - * Copyright (C) 2013, Robin Stocker <robin@nibor.org> and others + * Copyright (C) 2013, 2025 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 @@ -539,7 +539,7 @@ public void testAssumeUnchanged() throws Exception { assertTrue(diff.getAssumeUnchanged().contains("file3")); assertTrue(diff.getModified().contains("file")); - git.add().addFilepattern(".").call(); + git.add().addFilepattern(".").setAll(false).call(); iterator = new FileTreeIterator(db); diff = new IndexDiff(db, Constants.HEAD, iterator); @@ -551,6 +551,18 @@ public void testAssumeUnchanged() throws Exception { assertTrue(diff.getAssumeUnchanged().contains("file3")); assertTrue(diff.getChanged().contains("file")); assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); + + git.add().addFilepattern(".").call(); + + iterator = new FileTreeIterator(db); + diff = new IndexDiff(db, Constants.HEAD, iterator); + diff.diff(); + assertEquals(1, diff.getAssumeUnchanged().size()); + assertEquals(0, diff.getModified().size()); + assertEquals(1, diff.getChanged().size()); + assertTrue(diff.getAssumeUnchanged().contains("file2")); + assertTrue(diff.getChanged().contains("file")); + assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java index 21032c3..d6f0b03 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
@@ -16,6 +16,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.nio.ByteBuffer; import java.util.Locale; import org.eclipse.jgit.errors.InvalidObjectIdException; @@ -153,4 +154,16 @@ public void testSetByte() { assertEquals(ObjectId.fromRaw(exp).name(), id.name()); } } + + @Test + public void test_toFromByteBuffer_raw() { + ObjectId oid = ObjectId + .fromString("ff00eedd003713bb1bb26b808ec9312548e73946"); + ByteBuffer anObject = ByteBuffer.allocate(Constants.OBJECT_ID_LENGTH); + oid.copyRawTo(anObject); + anObject.flip(); + + ObjectId actual = ObjectId.fromRaw(anObject); + assertEquals(oid.name(), actual.name()); + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java index 97da175..943a68b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PersonIdentTest.java
@@ -55,7 +55,8 @@ public void testNewIdentInstant() { p.getWhenAsInstant()); assertEquals("A U Thor <author@example.com> 1142878501 -0500", p.toExternalString()); - assertEquals(ZoneId.of("GMT-05:00"), p.getZoneId()); + assertEquals(ZoneId.of("GMT-05:00").getRules().getOffset( + Instant.ofEpochMilli(1142878501000L)), p.getZoneOffset()); } @Test @@ -69,7 +70,8 @@ public void testNewIdentInstant2() { p.getWhenAsInstant()); assertEquals("A U Thor <author@example.com> 1142878501 +0530", p.toExternalString()); - assertEquals(ZoneId.of("GMT+05:30"), p.getZoneId()); + assertEquals(ZoneId.of("GMT+05:30").getRules().getOffset( + Instant.ofEpochMilli(1142878501000L)), p.getZoneOffset()); } @SuppressWarnings("unused")
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java index b02f245..85f9612 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java
@@ -71,6 +71,11 @@ public List<Ref> getAdditionalRefs() throws IOException { } @Override + public ReflogReader getReflogReader(Ref ref) throws IOException { + return null; + } + + @Override public void create() throws IOException { // Not needed }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java index 854180e..a93937e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
@@ -16,6 +16,9 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.storage.file.FileBasedConfig; @@ -24,22 +27,23 @@ public class ReflogConfigTest extends RepositoryTestCase { @Test public void testlogAllRefUpdates() throws Exception { - long commitTime = 1154236443000L; - int tz = -4 * 60; + Instant commitTime = Instant.ofEpochSecond(1154236443L); + ZoneOffset tz = ZoneOffset.ofHours(-4); // check that there are no entries in the reflog and turn off writing // reflogs - assertTrue(db.getReflogReader(Constants.HEAD).getReverseEntries() + RefDatabase refDb = db.getRefDatabase(); + assertTrue(refDb.getReflogReader(Constants.HEAD).getReverseEntries() .isEmpty()); - final FileBasedConfig cfg = db.getConfig(); + FileBasedConfig cfg = db.getConfig(); cfg.setBoolean("core", null, "logallrefupdates", false); cfg.save(); // do one commit and check that reflog size is 0: no reflogs should be // written commit("A Commit\n", commitTime, tz); - commitTime += 60 * 1000; - assertTrue("Reflog for HEAD still contain no entry", db + commitTime = commitTime.plus(Duration.ofMinutes(1)); + assertTrue("Reflog for HEAD still contain no entry", refDb .getReflogReader(Constants.HEAD).getReverseEntries().isEmpty()); // set the logAllRefUpdates parameter to true and check it @@ -52,10 +56,10 @@ public void testlogAllRefUpdates() throws Exception { // do one commit and check that reflog size is increased to 1 commit("A Commit\n", commitTime, tz); - commitTime += 60 * 1000; - assertTrue( - "Reflog for HEAD should contain one entry", - db.getReflogReader(Constants.HEAD).getReverseEntries().size() == 1); + commitTime = commitTime.plus(Duration.ofMinutes(1)); + assertTrue("Reflog for HEAD should contain one entry", + refDb.getReflogReader(Constants.HEAD).getReverseEntries() + .size() == 1); // set the logAllRefUpdates parameter to false and check it cfg.setBoolean("core", null, "logallrefupdates", false); @@ -67,10 +71,10 @@ public void testlogAllRefUpdates() throws Exception { // do one commit and check that reflog size is 2 commit("A Commit\n", commitTime, tz); - commitTime += 60 * 1000; - assertTrue( - "Reflog for HEAD should contain two entries", - db.getReflogReader(Constants.HEAD).getReverseEntries().size() == 2); + commitTime = commitTime.plus(Duration.ofMinutes(1)); + assertTrue("Reflog for HEAD should contain two entries", + refDb.getReflogReader(Constants.HEAD).getReverseEntries() + .size() == 2); // set the logAllRefUpdates parameter to false and check it cfg.setEnum("core", null, "logallrefupdates", @@ -84,13 +88,13 @@ public void testlogAllRefUpdates() throws Exception { // do one commit and check that reflog size is 3 commit("A Commit\n", commitTime, tz); assertTrue("Reflog for HEAD should contain three entries", - db.getReflogReader(Constants.HEAD).getReverseEntries() + refDb.getReflogReader(Constants.HEAD).getReverseEntries() .size() == 3); } - private void commit(String commitMsg, long commitTime, int tz) + private void commit(String commitMsg, Instant commitTime, ZoneOffset tz) throws IOException { - final CommitBuilder commit = new CommitBuilder(); + CommitBuilder commit = new CommitBuilder(); commit.setAuthor(new PersonIdent(author, commitTime, tz)); commit.setCommitter(new PersonIdent(committer, commitTime, tz)); commit.setMessage(commitMsg);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java index ae811f8..8865ba9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
@@ -15,6 +15,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.time.Instant; +import java.time.ZoneOffset; + import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.junit.RepositoryTestCase; @@ -162,7 +165,8 @@ private static ObjectId commit(final ObjectInserter odi, final ObjectId[] parentIds) throws Exception { final CommitBuilder c = new CommitBuilder(); c.setTreeId(treeB.writeTree(odi)); - c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0)); + c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", + Instant.ofEpochSecond(1), ZoneOffset.UTC)); c.setCommitter(c.getAuthor()); c.setParentIds(parentIds); c.setMessage("Tree " + c.getTreeId().name());
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 index f410960..b1998f3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/GitlinkMergeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/GitlinkMergeTest.java
@@ -15,6 +15,8 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.dircache.DirCache; @@ -357,7 +359,8 @@ 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.setAuthor(new PersonIdent("A U Thor", "a.u.thor", + Instant.ofEpochSecond(1), ZoneOffset.UTC)); c.setCommitter(c.getAuthor()); c.setParentIds(parentIds); c.setMessage("Tree " + c.getTreeId().name());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmUnionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmUnionTest.java new file mode 100644 index 0000000..3a8af7a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmUnionTest.java
@@ -0,0 +1,328 @@ +/* + * Copyright (C) 2024 Qualcomm Innovation Center, Inc. + * + * 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.merge; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.eclipse.jgit.diff.RawText; +import org.eclipse.jgit.diff.RawTextComparator; +import org.eclipse.jgit.lib.Constants; +import org.junit.Assume; +import org.junit.Test; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.runner.RunWith; + +@RunWith(Theories.class) +public class MergeAlgorithmUnionTest { + MergeFormatter fmt = new MergeFormatter(); + + private final boolean newlineAtEnd; + + @DataPoints + public static boolean[] newlineAtEndDataPoints = { false, true }; + + public MergeAlgorithmUnionTest(boolean newlineAtEnd) { + this.newlineAtEnd = newlineAtEnd; + } + + /** + * Check for a conflict where the second text was changed similar to the + * first one, but the second texts modification covers one more line. + * + * @throws java.io.IOException + */ + @Test + public void testTwoConflictingModifications() throws IOException { + assertEquals(t("abZZdefghij"), + merge("abcdefghij", "abZdefghij", "aZZdefghij")); + } + + /** + * Test a case where we have three consecutive chunks. The first text + * modifies all three chunks. The second text modifies the first and the + * last chunk. This should be reported as one conflicting region. + * + * @throws java.io.IOException + */ + @Test + public void testOneAgainstTwoConflictingModifications() throws IOException { + assertEquals(t("aZZcZefghij"), + merge("abcdefghij", "aZZZefghij", "aZcZefghij")); + } + + /** + * Test a merge where only the second text contains modifications. Expect as + * merge result the second text. + * + * @throws java.io.IOException + */ + @Test + public void testNoAgainstOneModification() throws IOException { + assertEquals(t("aZcZefghij"), + merge("abcdefghij", "abcdefghij", "aZcZefghij")); + } + + /** + * Both texts contain modifications but not on the same chunks. Expect a + * non-conflict merge result. + * + * @throws java.io.IOException + */ + @Test + public void testTwoNonConflictingModifications() throws IOException { + assertEquals(t("YbZdefghij"), + merge("abcdefghij", "abZdefghij", "Ybcdefghij")); + } + + /** + * Merge two complicated modifications. The merge algorithm has to extend + * and combine conflicting regions to get to the expected merge result. + * + * @throws java.io.IOException + */ + @Test + public void testTwoComplicatedModifications() throws IOException { + assertEquals(t("aZZZZfZhZjbYdYYYYiY"), + merge("abcdefghij", "aZZZZfZhZj", "abYdYYYYiY")); + } + + /** + * Merge two modifications with a shared delete at the end. The underlying + * diff algorithm has to provide consistent edit results to get the expected + * merge result. + * + * @throws java.io.IOException + */ + @Test + public void testTwoModificationsWithSharedDelete() throws IOException { + assertEquals(t("Cb}n}"), merge("ab}n}n}", "ab}n}", "Cb}n}")); + } + + /** + * Merge modifications with a shared insert in the middle. The underlying + * diff algorithm has to provide consistent edit results to get the expected + * merge result. + * + * @throws java.io.IOException + */ + @Test + public void testModificationsWithMiddleInsert() throws IOException { + assertEquals(t("aBcd123123uvwxPq"), + merge("abcd123uvwxpq", "aBcd123123uvwxPq", "abcd123123uvwxpq")); + } + + /** + * Merge modifications with a shared delete in the middle. The underlying + * diff algorithm has to provide consistent edit results to get the expected + * merge result. + * + * @throws java.io.IOException + */ + @Test + public void testModificationsWithMiddleDelete() throws IOException { + assertEquals(t("Abz}z123Q"), + merge("abz}z}z123q", "Abz}z123Q", "abz}z123q")); + } + + @Test + public void testInsertionAfterDeletion() throws IOException { + assertEquals(t("abcd"), merge("abd", "ad", "abcd")); + } + + @Test + public void testInsertionBeforeDeletion() throws IOException { + assertEquals(t("acbd"), merge("abd", "ad", "acbd")); + } + + /** + * Test a conflicting region at the very start of the text. + * + * @throws java.io.IOException + */ + @Test + public void testConflictAtStart() throws IOException { + assertEquals(t("ZYbcdefghij"), + merge("abcdefghij", "Zbcdefghij", "Ybcdefghij")); + } + + /** + * Test a conflicting region at the very end of the text. + * + * @throws java.io.IOException + */ + @Test + public void testConflictAtEnd() throws IOException { + assertEquals(t("abcdefghiZY"), + merge("abcdefghij", "abcdefghiZ", "abcdefghiY")); + } + + /** + * Check for a conflict where the second text was changed similar to the + * first one, but the second texts modification covers one more line. + * + * @throws java.io.IOException + */ + @Test + public void testSameModification() throws IOException { + assertEquals(t("abZdefghij"), + merge("abcdefghij", "abZdefghij", "abZdefghij")); + } + + /** + * Check that a deleted vs. a modified line shows up as conflict (see Bug + * 328551) + * + * @throws java.io.IOException + */ + @Test + public void testDeleteVsModify() throws IOException { + assertEquals(t("abZdefghij"), + merge("abcdefghij", "abdefghij", "abZdefghij")); + } + + @Test + public void testInsertVsModify() throws IOException { + assertEquals(t("abZXY"), merge("ab", "abZ", "aXY")); + } + + @Test + public void testAdjacentModifications() throws IOException { + assertEquals(t("aZcbYd"), merge("abcd", "aZcd", "abYd")); + } + + @Test + public void testSeparateModifications() throws IOException { + assertEquals(t("aZcYe"), merge("abcde", "aZcde", "abcYe")); + } + + @Test + public void testBlankLines() throws IOException { + assertEquals(t("aZc\nYe"), merge("abc\nde", "aZc\nde", "abc\nYe")); + } + + /** + * Test merging two contents which do one similar modification and one + * insertion is only done by one side, in the middle. Between modification + * and insertion is a block which is common between the two contents and the + * common base + * + * @throws java.io.IOException + */ + @Test + public void testTwoSimilarModsAndOneInsert() throws IOException { + assertEquals(t("aBcDde"), merge("abcde", "aBcde", "aBcDde")); + + assertEquals(t("IAAAJCAB"), merge("iACAB", "IACAB", "IAAAJCAB")); + + assertEquals(t("HIAAAJCAB"), merge("HiACAB", "HIACAB", "HIAAAJCAB")); + + assertEquals(t("AGADEFHIAAAJCAB"), + merge("AGADEFHiACAB", "AGADEFHIACAB", "AGADEFHIAAAJCAB")); + } + + /** + * Test merging two contents which do one similar modification and one + * insertion is only done by one side, at the end. Between modification and + * insertion is a block which is common between the two contents and the + * common base + * + * @throws java.io.IOException + */ + @Test + public void testTwoSimilarModsAndOneInsertAtEnd() throws IOException { + Assume.assumeTrue(newlineAtEnd); + assertEquals(t("IAAJ"), merge("iA", "IA", "IAAJ")); + + assertEquals(t("IAJ"), merge("iA", "IA", "IAJ")); + + assertEquals(t("IAAAJ"), merge("iA", "IA", "IAAAJ")); + } + + @Test + public void testTwoSimilarModsAndOneInsertAtEndNoNewlineAtEnd() + throws IOException { + Assume.assumeFalse(newlineAtEnd); + assertEquals(t("IAAAJ"), merge("iA", "IA", "IAAJ")); + + assertEquals(t("IAAJ"), merge("iA", "IA", "IAJ")); + + assertEquals(t("IAAAAJ"), merge("iA", "IA", "IAAAJ")); + } + + // Test situations where (at least) one input value is the empty text + + @Test + public void testEmptyTextModifiedAgainstDeletion() throws IOException { + // NOTE: git.git merge-file appends a '\n' to the end of the file even + // when the input files do not have a newline at the end. That appears + // to be a bug in git.git. + assertEquals(t("AB"), merge("A", "AB", "")); + assertEquals(t("AB"), merge("A", "", "AB")); + } + + @Test + public void testEmptyTextUnmodifiedAgainstDeletion() throws IOException { + assertEquals(t(""), merge("AB", "AB", "")); + + assertEquals(t(""), merge("AB", "", "AB")); + } + + @Test + public void testEmptyTextDeletionAgainstDeletion() throws IOException { + assertEquals(t(""), merge("AB", "", "")); + } + + private String merge(String commonBase, String ours, String theirs) + throws IOException { + MergeAlgorithm ma = new MergeAlgorithm(); + ma.setContentMergeStrategy(ContentMergeStrategy.UNION); + MergeResult<RawText> r = ma.merge(RawTextComparator.DEFAULT, + T(commonBase), T(ours), T(theirs)); + ByteArrayOutputStream bo = new ByteArrayOutputStream(50); + fmt.formatMerge(bo, r, "B", "O", "T", UTF_8); + return bo.toString(UTF_8); + } + + public String t(String text) { + StringBuilder r = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + switch (c) { + case '<': + r.append("<<<<<<< O\n"); + break; + case '=': + r.append("=======\n"); + break; + case '|': + r.append("||||||| B\n"); + break; + case '>': + r.append(">>>>>>> T\n"); + break; + default: + r.append(c); + if (newlineAtEnd || i < text.length() - 1) + r.append('\n'); + } + } + return r.toString(); + } + + public RawText T(String text) { + return new RawText(Constants.encode(t(text))); + } +}
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 3a036ac..c6a6321 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
@@ -1792,7 +1792,77 @@ public void checkModeMergeConflictInVirtualAncestor(MergeStrategy strategy) thro // children mergeResult = git.merge().include(commitC3S).call(); assertEquals(mergeResult.getMergeStatus(), MergeStatus.MERGED); + } + /** + * Merging two commits when binary files have equal content, but conflicting content in the + * virtual ancestor. + * + * <p> + * This test has the same set up as + * {@code checkFileDirMergeConflictInVirtualAncestor_NoConflictInChildren}, only + * with the content conflict in A1 and A2. + */ + @Theory + public void checkBinaryMergeConflictInVirtualAncestor(MergeStrategy strategy) throws Exception { + if (!strategy.equals(MergeStrategy.RECURSIVE)) { + return; + } + + Git git = Git.wrap(db); + + // master + writeTrashFile("c", "initial file"); + git.add().addFilepattern("c").call(); + RevCommit commitI = git.commit().setMessage("Initial commit").call(); + + writeTrashFile("a", "\0\1\1\1\1\0"); // content in Ancestor 1 + git.add().addFilepattern("a").call(); + RevCommit commitA1 = git.commit().setMessage("Ancestor 1").call(); + + writeTrashFile("a", "\0\1\2\3\4\5\0"); // content in Child 1 (commited on master) + git.add().addFilepattern("a").call(); + // commit C1M + git.commit().setMessage("Child 1 on master").call(); + + git.checkout().setCreateBranch(true).setStartPoint(commitI).setName("branch-to-merge").call(); + writeTrashFile("a", "\0\2\2\2\2\0"); // content in Ancestor 1 + git.add().addFilepattern("a").call(); + RevCommit commitA2 = git.commit().setMessage("Ancestor 2").call(); + + // second branch + git.checkout().setCreateBranch(true).setStartPoint(commitA1).setName("second-branch").call(); + writeTrashFile("a", "\0\5\4\3\2\1\0"); // content in Child 2 (commited on second-branch) + git.add().addFilepattern("a").call(); + // commit C2S + git.commit().setMessage("Child 2 on second-branch").call(); + + // Merge branch-to-merge into second-branch + MergeResult mergeResult = git.merge().include(commitA2).setStrategy(strategy).call(); + assertEquals(mergeResult.getNewHead(), null); + assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING); + // Resolve the conflict manually + writeTrashFile("a", "\0\3\3\3\3\0"); // merge conflict resolution + git.add().addFilepattern("a").call(); + RevCommit commitC3S = git.commit().setMessage("Child 3 on second bug - resolve merge conflict").call(); + + // Merge branch-to-merge into master + git.checkout().setName("master").call(); + mergeResult = git.merge().include(commitA2).setStrategy(strategy).call(); + assertEquals(mergeResult.getNewHead(), null); + assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING); + + // Resolve the conflict manually - set the same value as in resolution above + writeTrashFile("a", "\0\3\3\3\3\0"); // merge conflict resolution + git.add().addFilepattern("a").call(); + // commit C4M + git.commit().setMessage("Child 4 on master - resolve merge conflict").call(); + + // Merge C4M (second-branch) into master (C3S) + // Conflict in virtual base should be here, but there are no conflicts in + // children + mergeResult = git.merge().include(commitC3S).call(); + assertEquals(mergeResult.getMergeStatus(), MergeStatus.MERGED); } /**
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java index 798aebe..0016adf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
@@ -16,6 +16,8 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; @@ -375,7 +377,8 @@ 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.setAuthor(new PersonIdent("A U Thor", "a.u.thor", + Instant.ofEpochMilli(1L), ZoneOffset.UTC)); c.setCommitter(c.getAuthor()); c.setParentIds(parentIds); c.setMessage("Tree " + c.getTreeId().name());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java index 2aac15b..5507f85 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
@@ -48,8 +48,7 @@ import org.junit.runners.Suite; @RunWith(Suite.class) -@Suite.SuiteClasses({ - PatchApplierTest.WithWorktree. class, // +@Suite.SuiteClasses({ PatchApplierTest.WithWorktree.class, // PatchApplierTest.InCore.class, // }) public class PatchApplierTest { @@ -128,6 +127,20 @@ protected Result applyPatch() throws IOException { } } + protected Result applyPatchAllowConflicts() throws IOException { + InputStream patchStream = getTestResource(name + ".patch"); + Patch patch = new Patch(); + patch.parse(patchStream); + if (inCore) { + try (ObjectInserter oi = db.newObjectInserter()) { + return new PatchApplier(db, baseTip, oi).allowConflicts() + .applyPatch(patch); + } + } + return new PatchApplier(db).allowConflicts() + .applyPatch(patch); + } + protected static InputStream getTestResource(String patchFile) { return PatchApplierTest.class.getClassLoader() .getResourceAsStream("org/eclipse/jgit/diff/" + patchFile); @@ -169,6 +182,13 @@ void verifyChange(Result result, String aName, boolean exists) verifyContent(result, aName, exists); } + void verifyChange(Result result, String aName, boolean exists, + int numConflicts) throws Exception { + assertEquals(numConflicts, result.getErrors().size()); + assertEquals(1, result.getPaths().size()); + verifyContent(result, aName, exists); + } + protected byte[] readBlob(ObjectId treeish, String path) throws Exception { try (TestRepository<?> tr = new TestRepository<>(db); @@ -346,6 +366,44 @@ public void testCopyWithHunks() throws Exception { } @Test + public void testConflictMarkers() throws Exception { + init("allowconflict", true, true); + + Result result = applyPatchAllowConflicts(); + + assertEquals(result.getErrors().size(), 1); + PatchApplier.Result.Error error = result.getErrors().get(0); + assertEquals("cannot apply hunk", error.msg); + assertEquals("allowconflict", error.oldFileName); + assertTrue(error.isGitConflict()); + verifyChange(result, "allowconflict", true, 1); + } + + @Test + public void testConflictMarkersOutOfBounds() throws Exception { + init("ConflictOutOfBounds", true, true); + + Result result = applyPatchAllowConflicts(); + + assertEquals(result.getErrors().size(), 1); + PatchApplier.Result.Error error = result.getErrors().get(0); + assertEquals("cannot apply hunk", error.msg); + assertEquals("ConflictOutOfBounds", error.oldFileName); + assertTrue(error.isGitConflict()); + verifyChange(result, "ConflictOutOfBounds", true, 1); + } + + @Test + public void testConflictMarkersFileDeleted() throws Exception { + init("allowconflict_file_deleted", false, false); + + Result result = applyPatchAllowConflicts(); + + assertEquals(1, result.getErrors().size()); + assertEquals(0, result.getPaths().size()); + } + + @Test public void testShiftUp() throws Exception { init("ShiftUp");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java index 6872289..014ff92 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009, Google Inc. and others + * Copyright (C) 2008, 2024 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 @@ -23,7 +23,9 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; -import java.util.TimeZone; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.CommitBuilder; @@ -94,18 +96,17 @@ public void testParse_NoParents() throws Exception { assertNotNull(cAuthor); assertEquals(authorName, cAuthor.getName()); assertEquals(authorEmail, cAuthor.getEmailAddress()); - assertEquals((long) authorTime * 1000, cAuthor.getWhen().getTime()); - assertEquals(TimeZone.getTimeZone("GMT" + authorTimeZone), - cAuthor.getTimeZone()); + assertEquals(Instant.ofEpochSecond(authorTime), + cAuthor.getWhenAsInstant()); + assertEquals(ZoneId.of(authorTimeZone), cAuthor.getZoneId()); final PersonIdent cCommitter = c.getCommitterIdent(); assertNotNull(cCommitter); assertEquals(committerName, cCommitter.getName()); assertEquals(committerEmail, cCommitter.getEmailAddress()); - assertEquals((long) committerTime * 1000, - cCommitter.getWhen().getTime()); - assertEquals(TimeZone.getTimeZone("GMT" + committerTimeZone), - cCommitter.getTimeZone()); + assertEquals(Instant.ofEpochSecond(committerTime), + cCommitter.getWhenAsInstant()); + assertEquals(ZoneId.of(committerTimeZone), cCommitter.getZoneId()); } private RevCommit create(String msg) throws Exception { @@ -153,9 +154,13 @@ public void testParse_incompleteAuthorAndCommitter() throws Exception { c.parseCanonical(rw, b.toString().getBytes(UTF_8)); } assertEquals( - new PersonIdent("", "a_u_thor@example.com", 1218123387000L, 7), + new PersonIdent("", "a_u_thor@example.com", + Instant.ofEpochMilli(1218123387000L), + ZoneOffset.ofHoursMinutes(0, 7)), c.getAuthorIdent()); - assertEquals(new PersonIdent("", "", 1218123390000L, -5), + assertEquals( + new PersonIdent("", "", Instant.ofEpochMilli(1218123390000L), + ZoneOffset.ofHoursMinutes(0, -5)), c.getCommitterIdent()); } @@ -408,6 +413,7 @@ public void testParse_NoMessage() throws Exception { final RevCommit c = create(msg); assertEquals(msg, c.getFullMessage()); assertEquals(msg, c.getShortMessage()); + assertEquals(msg, c.getFirstMessageLine()); } @Test @@ -415,6 +421,7 @@ public void testParse_OnlyLFMessage() throws Exception { final RevCommit c = create("\n"); assertEquals("\n", c.getFullMessage()); assertEquals("", c.getShortMessage()); + assertEquals("", c.getFirstMessageLine()); } @Test @@ -423,6 +430,7 @@ public void testParse_ShortLineOnlyNoLF() throws Exception { final RevCommit c = create(shortMsg); assertEquals(shortMsg, c.getFullMessage()); assertEquals(shortMsg, c.getShortMessage()); + assertEquals(shortMsg, c.getFirstMessageLine()); } @Test @@ -432,6 +440,7 @@ public void testParse_ShortLineOnlyEndLF() throws Exception { final RevCommit c = create(fullMsg); assertEquals(fullMsg, c.getFullMessage()); assertEquals(shortMsg, c.getShortMessage()); + assertEquals(shortMsg, c.getFirstMessageLine()); } @Test @@ -441,6 +450,7 @@ public void testParse_ShortLineOnlyEmbeddedLF() throws Exception { final RevCommit c = create(fullMsg); assertEquals(fullMsg, c.getFullMessage()); assertEquals(shortMsg, c.getShortMessage()); + assertEquals("This is a", c.getFirstMessageLine()); } @Test @@ -450,6 +460,7 @@ public void testParse_ShortLineOnlyEmbeddedAndEndingLF() throws Exception { final RevCommit c = create(fullMsg); assertEquals(fullMsg, c.getFullMessage()); assertEquals(shortMsg, c.getShortMessage()); + assertEquals("This is a", c.getFirstMessageLine()); } @Test @@ -461,6 +472,7 @@ public void testParse_GitStyleMessage() throws Exception { final RevCommit c = create(fullMsg); assertEquals(fullMsg, c.getFullMessage()); assertEquals(shortMsg, c.getShortMessage()); + assertEquals(shortMsg, c.getFirstMessageLine()); } @Test @@ -480,6 +492,7 @@ public void testParse_PublicParseMethod() assertEquals(author, p.getAuthorIdent()); assertEquals(committer, p.getCommitterIdent()); assertEquals("Test commit", p.getShortMessage()); + assertEquals("Test commit", p.getFirstMessageLine()); assertEquals(src.getMessage(), p.getFullMessage()); } @@ -494,6 +507,7 @@ public void testParse_GitStyleMessageWithCRLF() throws Exception { final RevCommit c = create(fullMsg); assertEquals(fullMsg, c.getFullMessage()); assertEquals(shortMsg, c.getShortMessage()); + assertEquals("This fixes a", c.getFirstMessageLine()); } private static ObjectId id(String str) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java index 81ff4a2..7fece66 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertNull; import java.io.IOException; +import java.time.Instant; import java.util.Date; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -217,14 +218,132 @@ public void testCommitTimeRevFilter() throws Exception { final RevCommit b = commit(a); tick(100); - Date since = getDate(); + Instant since = getInstant(); final RevCommit c1 = commit(b); tick(100); final RevCommit c2 = commit(b); tick(100); - Date until = getDate(); + Instant until = getInstant(); + final RevCommit d = commit(c1, c2); + tick(100); + + final RevCommit e = commit(d); + + { + RevFilter after = CommitTimeRevFilter.after(since); + assertNotNull(after); + rw.setRevFilter(after); + markStart(e); + assertCommit(e, rw.next()); + assertCommit(d, rw.next()); + assertCommit(c2, rw.next()); + assertCommit(c1, rw.next()); + assertNull(rw.next()); + } + + { + RevFilter before = CommitTimeRevFilter.before(until); + assertNotNull(before); + rw.reset(); + rw.setRevFilter(before); + markStart(e); + assertCommit(c2, rw.next()); + assertCommit(c1, rw.next()); + assertCommit(b, rw.next()); + assertCommit(a, rw.next()); + assertNull(rw.next()); + } + + { + RevFilter between = CommitTimeRevFilter.between(since, until); + assertNotNull(between); + rw.reset(); + rw.setRevFilter(between); + markStart(e); + assertCommit(c2, rw.next()); + assertCommit(c1, rw.next()); + assertNull(rw.next()); + } + } + + @Test + public void testCommitTimeRevFilter_date() throws Exception { + // Using deprecated Date api for the commit time rev filter. + // Delete this tests when method is removed. + final RevCommit a = commit(); + tick(100); + + final RevCommit b = commit(a); + tick(100); + + Date since = Date.from(getInstant()); + final RevCommit c1 = commit(b); + tick(100); + + final RevCommit c2 = commit(b); + tick(100); + + Date until = Date.from(getInstant()); + final RevCommit d = commit(c1, c2); + tick(100); + + final RevCommit e = commit(d); + + { + RevFilter after = CommitTimeRevFilter.after(since); + assertNotNull(after); + rw.setRevFilter(after); + markStart(e); + assertCommit(e, rw.next()); + assertCommit(d, rw.next()); + assertCommit(c2, rw.next()); + assertCommit(c1, rw.next()); + assertNull(rw.next()); + } + + { + RevFilter before = CommitTimeRevFilter.before(until); + assertNotNull(before); + rw.reset(); + rw.setRevFilter(before); + markStart(e); + assertCommit(c2, rw.next()); + assertCommit(c1, rw.next()); + assertCommit(b, rw.next()); + assertCommit(a, rw.next()); + assertNull(rw.next()); + } + + { + RevFilter between = CommitTimeRevFilter.between(since, until); + assertNotNull(between); + rw.reset(); + rw.setRevFilter(between); + markStart(e); + assertCommit(c2, rw.next()); + assertCommit(c1, rw.next()); + assertNull(rw.next()); + } + } + + @Test + public void testCommitTimeRevFilter_long() throws Exception { + final RevCommit a = commit(); + tick(100); + + final RevCommit b = commit(a); + tick(100); + + long since = getInstant().toEpochMilli(); + final RevCommit c1 = commit(b); + tick(100); + + final RevCommit c2 = commit(b); + tick(100); + + long until = getInstant().toEpochMilli(); final RevCommit d = commit(c1, c2); tick(100);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java index ec0c0e7..8fa6a83 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
@@ -12,6 +12,7 @@ import static org.junit.Assert.assertSame; +import java.time.Instant; import java.util.Date; import org.eclipse.jgit.dircache.DirCacheEntry; @@ -38,8 +39,14 @@ protected RevWalk createRevWalk() { return new RevWalk(db); } + // Use getInstant() instead + @Deprecated protected Date getDate() { - return util.getDate(); + return Date.from(util.getInstant()); + } + + protected Instant getInstant() { + return util.getInstant(); } protected void tick(int secDelta) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java index 0a045c9..ffc7c96 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertEquals; import java.util.Collection; +import java.util.HashSet; import java.util.List; import org.eclipse.jgit.api.Git; @@ -121,7 +122,7 @@ private void assertContains(RevCommit commit, Collection<Ref> refsThatShouldCont Collection<Ref> sortedRefs = RefComparator.sort(allRefs); List<Ref> actual = RevWalkUtils.findBranchesReachableFrom(commit, rw, sortedRefs); - assertEquals(refsThatShouldContainCommit, actual); + assertEquals(new HashSet<>(refsThatShouldContainCommit), new HashSet<>(actual)); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java index 300c869..4306975 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
@@ -114,6 +114,13 @@ public void addSubmodule() throws Exception { try (Repository subModRepo = generator.getRepository()) { assertNotNull(subModRepo); assertEquals(subCommit, commit); + String worktreeDir = subModRepo.getConfig().getString( + ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_WORKTREE); + assertEquals("../../../sub", worktreeDir); + String gitdir = read(new File(subModRepo.getWorkTree(), + Constants.DOT_GIT)); + assertEquals("gitdir: ../.git/modules/sub", gitdir); } } Status status = Git.wrap(db).status().call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java index b10bd73..d541170 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java
@@ -17,21 +17,25 @@ import java.io.IOException; import java.util.Collection; +import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.InitCommand; +import org.eclipse.jgit.api.SubmoduleAddCommand; import org.eclipse.jgit.api.SubmoduleUpdateCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.junit.Test; @@ -40,6 +44,91 @@ */ public class SubmoduleUpdateTest extends RepositoryTestCase { + private Repository submoduleRepo; + + private Git git; + + private AnyObjectId subRepoCommit2; + + private void createSubmoduleRepo() throws IOException, GitAPIException { + File directory = createTempDirectory("submodule_repo"); + InitCommand init = Git.init(); + init.setDirectory(directory); + init.call(); + submoduleRepo = Git.open(directory).getRepository(); + try (Git sub = Git.wrap(submoduleRepo)) { + // commit something + JGitTestUtil.writeTrashFile(submoduleRepo, "commit1.txt", + "commit 1"); + sub.add().addFilepattern("commit1.txt").call(); + sub.commit().setMessage("commit 1").call().getId(); + + JGitTestUtil.writeTrashFile(submoduleRepo, "commit2.txt", + "commit 2"); + sub.add().addFilepattern("commit2.txt").call(); + subRepoCommit2 = sub.commit().setMessage("commit 2").call().getId(); + } + } + + private void addSubmodule(String path) throws GitAPIException { + SubmoduleAddCommand command = new SubmoduleAddCommand(db); + command.setPath(path); + String uri = submoduleRepo.getDirectory().toURI().toString(); + command.setURI(uri); + try (Repository repo = command.call()) { + assertNotNull(repo); + } + git.add().addFilepattern(path).addFilepattern(Constants.DOT_GIT_MODULES) + .call(); + git.commit().setMessage("adding submodule").call(); + recursiveDelete(new File(git.getRepository().getWorkTree(), path)); + recursiveDelete( + new File(new File(git.getRepository().getCommonDirectory(), + Constants.MODULES), path)); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + createSubmoduleRepo(); + + git = Git.wrap(db); + // commit something + writeTrashFile("initial.txt", "initial"); + git.add().addFilepattern("initial.txt").call(); + git.commit().setMessage("initial commit").call(); + } + + public void updateModeClonedRestoredSubmoduleTemplate(String mode) + throws Exception { + String path = "sub"; + addSubmodule(path); + + StoredConfig cfg = git.getRepository().getConfig(); + if (mode != null) { + cfg.load(); + cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, + ConfigConstants.CONFIG_KEY_UPDATE, mode); + cfg.save(); + } + SubmoduleUpdateCommand update = new SubmoduleUpdateCommand(db); + update.call(); + try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { + update.call(); + assertEquals(subRepoCommit2.getName(), + subGit.getRepository().getBranch()); + } + + recursiveDelete(new File(db.getWorkTree(), path)); + + update.call(); + try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { + update.call(); + assertEquals(subRepoCommit2.getName(), + subGit.getRepository().getBranch()); + } + } + @Test public void repositoryWithNoSubmodules() throws GitAPIException { SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); @@ -50,35 +139,9 @@ public void repositoryWithNoSubmodules() throws GitAPIException { @Test public void repositoryWithSubmodule() throws Exception { - writeTrashFile("file.txt", "content"); - Git git = Git.wrap(db); - git.add().addFilepattern("file.txt").call(); - final RevCommit commit = git.commit().setMessage("create file").call(); final String path = "sub"; - DirCache cache = db.lockDirCache(); - DirCacheEditor editor = cache.editor(); - editor.add(new PathEdit(path) { - - @Override - public void apply(DirCacheEntry ent) { - ent.setFileMode(FileMode.GITLINK); - ent.setObjectId(commit); - } - }); - editor.commit(); - - StoredConfig config = db.getConfig(); - config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, - ConfigConstants.CONFIG_KEY_URL, db.getDirectory().toURI() - .toString()); - config.save(); - - FileBasedConfig modulesConfig = new FileBasedConfig(new File( - db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); - modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, - ConfigConstants.CONFIG_KEY_PATH, path); - modulesConfig.save(); + addSubmodule(path); SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); Collection<String> updated = command.call(); @@ -90,14 +153,22 @@ public void apply(DirCacheEntry ent) { assertTrue(generator.next()); try (Repository subRepo = generator.getRepository()) { assertNotNull(subRepo); - assertEquals(commit, subRepo.resolve(Constants.HEAD)); + assertEquals(subRepoCommit2, subRepo.resolve(Constants.HEAD)); + String worktreeDir = subRepo.getConfig().getString( + ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_WORKTREE); + assertEquals("../../../sub", worktreeDir); + String gitdir = read( + new File(subRepo.getWorkTree(), Constants.DOT_GIT)); + assertEquals("gitdir: ../.git/modules/sub", gitdir); + } } } @Test - public void repositoryWithUnconfiguredSubmodule() throws IOException, - GitAPIException { + public void repositoryWithUnconfiguredSubmodule() + throws IOException, GitAPIException { final ObjectId id = ObjectId .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); final String path = "sub"; @@ -113,16 +184,14 @@ public void apply(DirCacheEntry ent) { }); editor.commit(); - FileBasedConfig modulesConfig = new FileBasedConfig(new File( - db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); + FileBasedConfig modulesConfig = new FileBasedConfig( + new File(db.getWorkTree(), Constants.DOT_GIT_MODULES), + db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_PATH, path); String url = "git://server/repo.git"; modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_URL, url); - String update = "rebase"; - modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, - ConfigConstants.CONFIG_KEY_UPDATE, update); modulesConfig.save(); SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); @@ -132,8 +201,8 @@ public void apply(DirCacheEntry ent) { } @Test - public void repositoryWithInitializedSubmodule() throws IOException, - GitAPIException { + public void repositoryWithInitializedSubmodule() + throws IOException, GitAPIException { final ObjectId id = ObjectId .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); final String path = "sub"; @@ -160,4 +229,77 @@ public void apply(DirCacheEntry ent) { assertNotNull(updated); assertTrue(updated.isEmpty()); } + + @Test + public void updateModeMergeClonedRestoredSubmodule() throws Exception { + updateModeClonedRestoredSubmoduleTemplate( + ConfigConstants.CONFIG_KEY_MERGE); + } + + @Test + public void updateModeRebaseClonedRestoredSubmodule() throws Exception { + updateModeClonedRestoredSubmoduleTemplate( + ConfigConstants.CONFIG_KEY_REBASE); + } + + @Test + public void updateModeCheckoutClonedRestoredSubmodule() throws Exception { + updateModeClonedRestoredSubmoduleTemplate( + ConfigConstants.CONFIG_KEY_CHECKOUT); + } + + @Test + public void updateModeMissingClonedRestoredSubmodule() throws Exception { + updateModeClonedRestoredSubmoduleTemplate(null); + } + + @Test + public void updateMode() throws Exception { + String path = "sub"; + addSubmodule(path); + + StoredConfig cfg = git.getRepository().getConfig(); + cfg.load(); + cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, + ConfigConstants.CONFIG_KEY_UPDATE, + ConfigConstants.CONFIG_KEY_REBASE); + cfg.save(); + + SubmoduleUpdateCommand update = new SubmoduleUpdateCommand(db); + update.call(); + try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { + CheckoutCommand checkout = subGit.checkout(); + checkout.setName("master"); + checkout.call(); + update.call(); + assertEquals("master", subGit.getRepository().getBranch()); + } + + cfg.load(); + cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, + ConfigConstants.CONFIG_KEY_UPDATE, + ConfigConstants.CONFIG_KEY_CHECKOUT); + cfg.save(); + + update.call(); + try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { + assertEquals(subRepoCommit2.getName(), + subGit.getRepository().getBranch()); + } + + cfg.load(); + cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, + ConfigConstants.CONFIG_KEY_UPDATE, + ConfigConstants.CONFIG_KEY_MERGE); + cfg.save(); + + update.call(); + try (Git subGit = Git.open(new File(db.getWorkTree(), path))) { + CheckoutCommand checkout = subGit.checkout(); + checkout.setName("master"); + checkout.call(); + update.call(); + assertEquals("master", subGit.getRepository().getBranch()); + } + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java index c47e591..0ba8926 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java
@@ -25,10 +25,6 @@ import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.transport.resolver.ReceivePackFactory; -import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; -import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -46,16 +42,8 @@ public class AtomicPushTest { public void setUp() throws Exception { server = newRepo("server"); client = newRepo("client"); - testProtocol = new TestProtocol<>( - null, - new ReceivePackFactory<Object>() { - @Override - public ReceivePack create(Object req, Repository db) - throws ServiceNotEnabledException, - ServiceNotAuthorizedException { - return new ReceivePack(db); - } - }); + testProtocol = new TestProtocol<>(null, + (req, db) -> new ReceivePack(db)); uri = testProtocol.register(ctx, server); try (TestRepository<?> clientRepo = new TestRepository<>(client)) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java index cee023d..6290b79 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateIdentTest.java
@@ -138,6 +138,51 @@ public void incompleteCasesMatchPersonIdent() throws Exception { "Me <me@example.com>"); } + @Test + public void timezoneRange_hours() { + int HOUR_TO_MS = 60 * 60 * 1000; + + // java.util.TimeZone: Hours must be between 0 to 23 + PushCertificateIdent hourLimit = PushCertificateIdent + .parse("A U. Thor <a_u_thor@example.com> 1218123387 +2300"); + assertEquals(1380, hourLimit.getTimeZoneOffset()); + assertEquals(23 * HOUR_TO_MS, + hourLimit.getTimeZone().getOffset(1218123387)); + + PushCertificateIdent hourDubious = PushCertificateIdent + .parse("A U. Thor <a_u_thor@example.com> 1218123387 +2400"); + assertEquals(1440, hourDubious.getTimeZoneOffset()); + assertEquals(0, hourDubious.getTimeZone().getOffset(1218123387)); + } + + @Test + public void timezoneRange_minutes() { + PushCertificateIdent hourLimit = PushCertificateIdent + .parse("A U. Thor <a_u_thor@example.com> 1218123387 +0059"); + assertEquals(59, hourLimit.getTimeZoneOffset()); + assertEquals(59 * 60 * 1000, + hourLimit.getTimeZone().getOffset(1218123387)); + + // This becomes one hour and one minute (!) + PushCertificateIdent hourDubious = PushCertificateIdent + .parse("A U. Thor <a_u_thor@example.com> 1218123387 +0061"); + assertEquals(61, hourDubious.getTimeZoneOffset()); + assertEquals(61 * 60 * 1000, + hourDubious.getTimeZone().getOffset(1218123387)); + + PushCertificateIdent weirdCase = PushCertificateIdent + .parse("A U. Thor <a_u_thor@example.com> 1218123387 +0099"); + assertEquals(99, weirdCase.getTimeZoneOffset()); + assertEquals(99 * 60 * 1000, + weirdCase.getTimeZone().getOffset(1218123387)); + + PushCertificateIdent weirdCase2 = PushCertificateIdent + .parse("A U. Thor <a_u_thor@example.com> 1218123387 +0199"); + assertEquals(60 + 99, weirdCase2.getTimeZoneOffset()); + assertEquals((60 + 99) * 60 * 1000, + weirdCase2.getTimeZone().getOffset(1218123387)); + } + private static void assertMatchesPersonIdent(String raw, PersonIdent expectedPersonIdent, String expectedUserId) { PushCertificateIdent certIdent = PushCertificateIdent.parse(raw);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java index 4f01e4d..a03222b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java
@@ -23,6 +23,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -318,8 +320,8 @@ public void putMatchingWithSomeMatchingRefs() throws Exception { } private PersonIdent newIdent() { - return new PersonIdent( - "A U. Thor", "author@example.com", ts.getAndIncrement(), 0); + return new PersonIdent("A U. Thor", "author@example.com", + Instant.ofEpochMilli(ts.getAndIncrement()), ZoneOffset.UTC); } private PushCertificateStore newStore() {
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 029b45e..96d3a58 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
@@ -14,10 +14,10 @@ import java.io.File; import java.io.IOException; import java.net.HttpCookie; +import java.time.Duration; 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; @@ -101,7 +101,7 @@ public void testProcessResponseCookies() throws IOException { .singletonList("cookie2=some value; Max-Age=1234; Path=/")); try (TransportHttp transportHttp = new TransportHttp(db, uri)) { - Date creationDate = new Date(); + Instant creationDate = Instant.now(); transportHttp.processResponseCookies(connection); // evaluate written cookie file @@ -112,8 +112,9 @@ public void testProcessResponseCookies() throws IOException { cookie.setPath("/u/2/"); cookie.setMaxAge( - (Instant.parse("2100-01-01T11:00:00.000Z").toEpochMilli() - - creationDate.getTime()) / 1000); + Duration.between(creationDate, + Instant.parse("2100-01-01T11:00:00.000Z")) + .getSeconds()); cookie.setSecure(true); cookie.setHttpOnly(true); expectedCookies.add(cookie);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java index d403624..6792002 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
@@ -82,6 +82,43 @@ public void testWindowsFile2() throws Exception { } @Test + public void testBrokenFilePath() throws Exception { + String str = "D:\\\\my\\\\x"; + URIish u = new URIish(str); + assertNull(u.getScheme()); + assertFalse(u.isRemote()); + assertEquals(str, u.getPath()); + assertEquals(u, new URIish(str)); + } + + @Test + public void testStackOverflow() throws Exception { + StringBuilder b = new StringBuilder("D:\\"); + for (int i = 0; i < 4000; i++) { + b.append("x\\"); + } + String str = b.toString(); + URIish u = new URIish(str); + assertNull(u.getScheme()); + assertFalse(u.isRemote()); + assertEquals(str, u.getPath()); + } + + @Test + public void testStackOverflow2() throws Exception { + StringBuilder b = new StringBuilder("D:\\"); + for (int i = 0; i < 4000; i++) { + b.append("x\\"); + } + b.append('y'); + String str = b.toString(); + URIish u = new URIish(str); + assertNull(u.getScheme()); + assertFalse(u.isRemote()); + assertEquals(str, u.getPath()); + } + + @Test public void testRelativePath() throws Exception { final String str = "../../foo/bar"; URIish u = new URIish(str);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java index 2711762..a5507c8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java
@@ -27,9 +27,6 @@ import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.transport.UploadPack.RequestPolicy; -import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; -import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; -import org.eclipse.jgit.transport.resolver.UploadPackFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -264,15 +261,10 @@ private void generateBitmaps(InMemoryRepository repo) throws Exception { } private static TestProtocol<Object> generateReachableCommitUploadPackProtocol() { - return new TestProtocol<>(new UploadPackFactory<Object>() { - @Override - public UploadPack create(Object req, Repository db) - throws ServiceNotEnabledException, - ServiceNotAuthorizedException { - UploadPack up = new UploadPack(db); - up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT); - return up; - } + return new TestProtocol<>((req, db) -> { + UploadPack up = new UploadPack(db); + up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT); + return up; }, null); } }
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 def73ac..5c2f0e5 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
@@ -1,5 +1,6 @@ package org.eclipse.jgit.transport; +import static java.time.ZoneOffset.UTC; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; @@ -11,12 +12,14 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; 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.io.InputStream; import java.io.StringWriter; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -501,15 +504,15 @@ public void testV2Capabilities() throws Exception { assertThat(hook.capabilitiesRequest, notNullValue()); assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString(), - pckIn.readString()), + Arrays.asList(pckIn.readString(),pckIn.readString(), + pckIn.readString(), pckIn.readString()), // TODO(jonathantanmy) This check is written this way // to make it simple to see that we expect this list of // capabilities, but probably should be loosened to // allow additional commands to be added to the list, // and additional capabilities to be added to existing // commands without requiring test changes. - hasItems("ls-refs", "fetch=shallow", "server-option")); + hasItems("agent=" + UserAgent.get() ,"ls-refs", "fetch=shallow", "server-option")); assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @@ -535,7 +538,7 @@ private void checkAdvertisedIfAllowed(String configSection, String configName, lines.add(line); } } - assertThat(lines, containsInAnyOrder("ls-refs", "fetch", "server-option")); + assertThat(lines, containsInAnyOrder("ls-refs", "fetch", "server-option", "agent=" + UserAgent.get())); } private void checkUnadvertisedIfUnallowed(String configSection, @@ -564,6 +567,47 @@ private void checkUnadvertisedIfUnallowed(String configSection, } @Test + public void testV0CapabilitiesAllowAnySha1InWant() throws Exception { + checkAvertisedCapabilityProtocolV0IfAllowed("uploadpack", + "allowanysha1inwant", "allow-reachable-sha1-in-want", + "allow-tip-sha1-in-want"); + } + + @Test + public void testV0CapabilitiesAllowReachableSha1InWant() throws Exception { + checkAvertisedCapabilityProtocolV0IfAllowed("uploadpack", + "allowreachablesha1inwant", "allow-reachable-sha1-in-want"); + } + + @Test + public void testV0CapabilitiesAllowTipSha1InWant() throws Exception { + checkAvertisedCapabilityProtocolV0IfAllowed("uploadpack", + "allowtipsha1inwant", "allow-tip-sha1-in-want"); + } + + private void checkAvertisedCapabilityProtocolV0IfAllowed( + String configSection, String configName, String... capabilities) + throws Exception { + server.getConfig().setBoolean(configSection, null, configName, true); + ByteArrayInputStream recvStream = uploadPackSetup( + TransferConfig.ProtocolVersion.V0.version(), null, + PacketLineIn.end()); + PacketLineIn pckIn = new PacketLineIn(recvStream); + + String line; + while (!PacketLineIn.isEnd((line = pckIn.readString()))) { + if (line.contains("capabilities")) { + List<String> linesCapabilities = Arrays.asList(line.substring( + line.indexOf(" ", line.indexOf("capabilities")) + 1) + .split(" ")); + assertThat(linesCapabilities, hasItems(capabilities)); + return; + } + } + fail("Server side protocol did not contain any capabilities'"); + } + + @Test public void testV2CapabilitiesAllowFilter() throws Exception { checkAdvertisedIfAllowed("uploadpack", "allowfilter", "filter"); checkUnadvertisedIfUnallowed("uploadpack", "allowfilter", "filter"); @@ -601,9 +645,9 @@ public void testV2CapabilitiesRefInWantNotAdvertisedIfAdvertisingForbidden() thr assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString(), + Arrays.asList(pckIn.readString(),pckIn.readString(), pckIn.readString(), pckIn.readString()), - hasItems("ls-refs", "fetch=shallow", "server-option")); + hasItems("agent="+ UserAgent.get(),"ls-refs", "fetch=shallow", "server-option")); assertTrue(PacketLineIn.isEnd(pckIn.readString())); } @@ -1464,14 +1508,19 @@ public void testV2FetchDeepenWithoutDone() throws Exception { public void testV2FetchShallowSince() throws Exception { PersonIdent person = new PersonIdent(remote.getRepository()); - RevCommit beyondBoundary = remote.commit() - .committer(new PersonIdent(person, 1510000000, 0)).create(); - RevCommit boundary = remote.commit().parent(beyondBoundary) - .committer(new PersonIdent(person, 1520000000, 0)).create(); - RevCommit tooOld = remote.commit() - .committer(new PersonIdent(person, 1500000000, 0)).create(); + RevCommit beyondBoundary = remote.commit().committer( + new PersonIdent(person, Instant.ofEpochSecond(1510000), UTC)) + .create(); + RevCommit boundary = remote.commit().parent(beyondBoundary).committer( + new PersonIdent(person, Instant.ofEpochSecond(1520000), UTC)) + .create(); + RevCommit tooOld = remote.commit().committer( + new PersonIdent(person, Instant.ofEpochSecond(1500000), UTC)) + .create(); RevCommit merge = remote.commit().parent(boundary).parent(tooOld) - .committer(new PersonIdent(person, 1530000000, 0)).create(); + .committer(new PersonIdent(person, + Instant.ofEpochSecond(1530000), UTC)) + .create(); remote.update("branch1", merge); @@ -1517,12 +1566,15 @@ public void testV2FetchShallowSince() throws Exception { public void testV2FetchShallowSince_excludedParentWithMultipleChildren() throws Exception { PersonIdent person = new PersonIdent(remote.getRepository()); - RevCommit base = remote.commit() - .committer(new PersonIdent(person, 1500000000, 0)).create(); - RevCommit child1 = remote.commit().parent(base) - .committer(new PersonIdent(person, 1510000000, 0)).create(); - RevCommit child2 = remote.commit().parent(base) - .committer(new PersonIdent(person, 1520000000, 0)).create(); + RevCommit base = remote.commit().committer( + new PersonIdent(person, Instant.ofEpochSecond(1500000), UTC)) + .create(); + RevCommit child1 = remote.commit().parent(base).committer( + new PersonIdent(person, Instant.ofEpochSecond(1510000), UTC)) + .create(); + RevCommit child2 = remote.commit().parent(base).committer( + new PersonIdent(person, Instant.ofEpochSecond(1520000), UTC)) + .create(); remote.update("branch1", child1); remote.update("branch2", child2); @@ -1559,8 +1611,9 @@ public void testV2FetchShallowSince_excludedParentWithMultipleChildren() throws public void testV2FetchShallowSince_noCommitsSelected() throws Exception { PersonIdent person = new PersonIdent(remote.getRepository()); - RevCommit tooOld = remote.commit() - .committer(new PersonIdent(person, 1500000000, 0)).create(); + RevCommit tooOld = remote.commit().committer( + new PersonIdent(person, Instant.ofEpochSecond(1500000), UTC)) + .create(); remote.update("branch1", tooOld); @@ -1684,12 +1737,15 @@ public void testV2FetchDeepenNot_supportAnnotatedTags() throws Exception { public void testV2FetchDeepenNot_excludedParentWithMultipleChildren() throws Exception { PersonIdent person = new PersonIdent(remote.getRepository()); - RevCommit base = remote.commit() - .committer(new PersonIdent(person, 1500000000, 0)).create(); - RevCommit child1 = remote.commit().parent(base) - .committer(new PersonIdent(person, 1510000000, 0)).create(); - RevCommit child2 = remote.commit().parent(base) - .committer(new PersonIdent(person, 1520000000, 0)).create(); + RevCommit base = remote.commit().committer( + new PersonIdent(person, Instant.ofEpochSecond(1500000), UTC)) + .create(); + RevCommit child1 = remote.commit().parent(base).committer( + new PersonIdent(person, Instant.ofEpochSecond(1510000), UTC)) + .create(); + RevCommit child2 = remote.commit().parent(base).committer( + new PersonIdent(person, Instant.ofEpochSecond(1520000), UTC)) + .create(); remote.update("base", base); remote.update("branch1", child1); @@ -2820,7 +2876,7 @@ public void testSingleBranchCloneTagChain() throws Exception { RevTag heavyTag2 = remote.tag("middleTagRing", heavyTag1); remote.lightweightTag("refTagRing", heavyTag2); - UploadPack uploadPack = new UploadPack(remote.getRepository()); + try (UploadPack uploadPack = new UploadPack(remote.getRepository())) { ByteArrayOutputStream cli = new ByteArrayOutputStream(); PacketLineOut clientWant = new PacketLineOut(cli); @@ -2830,7 +2886,6 @@ public void testSingleBranchCloneTagChain() throws Exception { clientWant.writeString("done\n"); try (ByteArrayOutputStream serverResponse = new ByteArrayOutputStream()) { - uploadPack.setPreUploadHook(new PreUploadHook() { @Override public void onBeginNegotiateRound(UploadPack up, @@ -2883,6 +2938,7 @@ public void onSendPack(UploadPack up, assertTrue(objDb.has(heavyTag2.toObjectId())); } } +} @Test public void testSingleBranchShallowCloneTagChainWithReflessTag() throws Exception { @@ -2894,7 +2950,7 @@ public void testSingleBranchShallowCloneTagChainWithReflessTag() throws Exceptio RevTag tag3 = remote.tag("t3", tag2); remote.lightweightTag("t3", tag3); - UploadPack uploadPack = new UploadPack(remote.getRepository()); + try (UploadPack uploadPack = new UploadPack(remote.getRepository())) { ByteArrayOutputStream cli = new ByteArrayOutputStream(); PacketLineOut clientWant = new PacketLineOut(cli); @@ -2904,7 +2960,6 @@ public void testSingleBranchShallowCloneTagChainWithReflessTag() throws Exceptio clientWant.writeString("done\n"); try (ByteArrayOutputStream serverResponse = new ByteArrayOutputStream()) { - uploadPack.setPreUploadHook(new PreUploadHook() { @Override public void onBeginNegotiateRound(UploadPack up, @@ -2952,6 +3007,7 @@ public void onSendPack(UploadPack up, assertTrue(objDb.has(one.toObjectId())); } } +} @Test public void testSafeToClearRefsInFetchV0() throws Exception {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java index e463e90..7b9e70d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -25,8 +25,9 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.dircache.Checkout; import org.eclipse.jgit.dircache.DirCache; -import org.eclipse.jgit.dircache.DirCacheCheckout; +import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEntry; @@ -38,6 +39,7 @@ import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; @@ -303,11 +305,12 @@ public void testIsModifiedSymlinkAsFile() throws Exception { DirCacheEntry dce = db.readDirCache().getEntry("symlink"); dce.setFileMode(FileMode.SYMLINK); try (ObjectReader objectReader = db.newObjectReader()) { + Checkout checkout = new Checkout(db).setRecursiveDeletion(false); + checkout.checkout(dce, + new CheckoutMetadata(EolStreamType.DIRECT, null), + objectReader, null); WorkingTreeOptions options = db.getConfig() .get(WorkingTreeOptions.KEY); - DirCacheCheckout.checkoutEntry(db, dce, objectReader, false, null, - options); - FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), options); while (!fti.getEntryPathString().equals("symlink")) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java index 3265249..44e8632 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
@@ -12,7 +12,9 @@ import static org.junit.Assert.assertEquals; -import java.util.concurrent.TimeUnit; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.lib.ObjectId; @@ -53,9 +55,9 @@ public class ChangeIdUtilTest { MockSystemReader mockSystemReader = new MockSystemReader(); - final long when = mockSystemReader.getCurrentTime(); + Instant when = mockSystemReader.now(); - final int tz = new MockSystemReader().getTimezone(when); + ZoneId tz = new MockSystemReader().getTimeZoneAt(when); PersonIdent author = new PersonIdent("J. Author", "ja@example.com"); { @@ -218,23 +220,23 @@ public void testACommitWithSubject_NonFooterAndBugAndSob() throws Exception { @Test public void testACommitWithSubjectBodyBugBrackersAndSob() throws Exception { assertEquals( - "a commit with subject body, bug. brackers and sob\n\nText\n\nBug: 33\nChange-Id: I90ecb589bef766302532c3e00915e10114b00f62\n[bracket]\nSigned-off-by: me@you.too\n", - call("a commit with subject body, bug. brackers and sob\n\nText\n\nBug: 33\n[bracket]\nSigned-off-by: me@you.too\n\n")); + "a commit with subject body, bug, brackers and sob\n\nText\n\nBug: 33\n[bracket]\nChange-Id: I94dc6ed919a4baaa7c1bf8712717b888c6b90363\nSigned-off-by: me@you.too\n", + call("a commit with subject body, bug, brackers and sob\n\nText\n\nBug: 33\n[bracket]\nSigned-off-by: me@you.too\n\n")); } @Test public void testACommitWithSubjectBodyBugLineWithASpaceAndSob() throws Exception { assertEquals( - "a commit with subject body, bug. line with a space and sob\n\nText\n\nBug: 33\nChange-Id: I864e2218bdee033c8ce9a7f923af9e0d5dc16863\n \nSigned-off-by: me@you.too\n", - call("a commit with subject body, bug. line with a space and sob\n\nText\n\nBug: 33\n \nSigned-off-by: me@you.too\n\n")); + "a commit with subject body, bug, line with a space and sob\n\nText\n\nBug: 33\n \nChange-Id: I126b472d2e0e64ad8187d61857f0169f9ccdae86\nSigned-off-by: me@you.too\n", + call("a commit with subject body, bug, line with a space and sob\n\nText\n\nBug: 33\n \nSigned-off-by: me@you.too\n\n")); } @Test public void testACommitWithSubjectBodyBugEmptyLineAndSob() throws Exception { assertEquals( - "a commit with subject body, bug. empty line and sob\n\nText\n\nBug: 33\nChange-Id: I33f119f533313883e6ada3df600c4f0d4db23a76\n \nSigned-off-by: me@you.too\n", - call("a commit with subject body, bug. empty line and sob\n\nText\n\nBug: 33\n \nSigned-off-by: me@you.too\n\n")); + "a commit with subject body, bug, empty line and sob\n\nText\n\nBug: 33\n\nChange-Id: Ic3b61b6e39a0815669b65302e9e75e6a5a019a26\nSigned-off-by: me@you.too\n", + call("a commit with subject body, bug, empty line and sob\n\nText\n\nBug: 33\n\nSigned-off-by: me@you.too\n\n")); } @Test @@ -342,9 +344,7 @@ public void testTimeAltersId() throws Exception { /** Increment the {@link #author} and {@link #committer} times. */ protected void tick() { - final long delta = TimeUnit.MILLISECONDS.convert(5 * 60, - TimeUnit.SECONDS); - final long now = author.getWhen().getTime() + delta; + Instant now = author.getWhenAsInstant().plus(Duration.ofMinutes(5)); author = new PersonIdent(author, now, tz); committer = new PersonIdent(committer, now, tz); @@ -528,7 +528,7 @@ public void testKernelStyleFooter() throws Exception { } @Test - public void testChangeIdAfterBugOrIssue() throws Exception { + public void testChangeIdAfterOtherFooters() throws Exception { assertEquals("a\n" + // "\n" + // "Bug: 42\n" + // @@ -541,6 +541,18 @@ public void testChangeIdAfterBugOrIssue() throws Exception { assertEquals("a\n" + // "\n" + // + "Bug: 42\n" + // + " multi-line Bug footer\n" + // + "Change-Id: Icc953ef35f1a4ee5eb945132aefd603ae3d9dd9f\n" + // + SOB1,// + call("a\n" + // + "\n" + // + "Bug: 42\n" + // + " multi-line Bug footer\n" + // + SOB1)); + + assertEquals("a\n" + // + "\n" + // "Issue: 42\n" + // "Change-Id: Ie66e07d89ae5b114c0975b49cf326e90331dd822\n" + // SOB1,// @@ -548,6 +560,14 @@ public void testChangeIdAfterBugOrIssue() throws Exception { "\n" + // "Issue: 42\n" + // SOB1)); + + assertEquals("a\n" + // + "\n" + // + "Other: none\n" + // + "Change-Id: Ide70e625dea61854206378a377dd12e462ae720f\n",// + call("a\n" + // + "\n" + // + "Other: none\n")); } @Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java index 6a531fe..7ef386f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateFormatterTest.java
@@ -89,7 +89,6 @@ public void RAW() { @Test public void LOCALE() { String date = new GitDateFormatter(Format.LOCALE).formatDate(ident); - System.out.println(date); assertTrue("Sep 20, 2011 7:09:25 PM -0400".equals(date) || "Sep 20, 2011, 7:09:25 PM -0400".equals(date) // JDK-8206961 || "Sep 20, 2011, 7:09:25\u202FPM -0400".equals(date)); // JDK-8304925 @@ -99,7 +98,6 @@ public void LOCALE() { public void LOCALELOCAL() { String date = new GitDateFormatter(Format.LOCALELOCAL) .formatDate(ident); - System.out.println(date); assertTrue("Sep 20, 2011 7:39:25 PM".equals(date) || "Sep 20, 2011, 7:39:25 PM".equals(date) // JDK-8206961 || "Sep 20, 2011, 7:39:25\u202FPM".equals(date)); // JDK-8304925
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitTimeParserBadlyFormattedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitTimeParserBadlyFormattedTest.java new file mode 100644 index 0000000..a59d7bc --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitTimeParserBadlyFormattedTest.java
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012, Christian Halstrick 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; + +import static org.junit.Assert.assertThrows; + +import java.text.ParseException; + +import org.eclipse.jgit.junit.MockSystemReader; +import org.junit.After; +import org.junit.Before; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; + +/** + * Tests which assert that unparseable Strings lead to ParseExceptions + */ +@RunWith(Theories.class) +public class GitTimeParserBadlyFormattedTest { + private String dateStr; + + @Before + public void setUp() { + MockSystemReader mockSystemReader = new MockSystemReader(); + SystemReader.setInstance(mockSystemReader); + } + + @After + public void tearDown() { + SystemReader.setInstance(null); + } + + public GitTimeParserBadlyFormattedTest(String dateStr) { + this.dateStr = dateStr; + } + + @DataPoints + public static String[] getDataPoints() { + return new String[] { "", ".", "...", "1970", "3000.3000.3000", "3 yesterday ago", + "now yesterday ago", "yesterdays", "3.day. 2.week.ago", + "day ago", "Gra Feb 21 15:35:00 2007 +0100", + "Sun Feb 21 15:35:00 2007 +0100", + "Wed Feb 21 15:35:00 Grand +0100" }; + } + + @Theory + public void badlyFormattedWithoutRef() { + assertThrows( + "The expected ParseException while parsing '" + dateStr + + "' did not occur.", + ParseException.class, () -> GitTimeParser.parse(dateStr)); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitTimeParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitTimeParserTest.java new file mode 100644 index 0000000..0e5eb28 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitTimeParserTest.java
@@ -0,0 +1,247 @@ +/* + * Copyright (C) 2024, Christian Halstrick 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.text.ParseException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.Period; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; + +import org.eclipse.jgit.junit.MockSystemReader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class GitTimeParserTest { + MockSystemReader mockSystemReader; + + @Before + public void setUp() { + mockSystemReader = new MockSystemReader(); + SystemReader.setInstance(mockSystemReader); + } + + @After + public void tearDown() { + SystemReader.setInstance(null); + } + + @Test + public void yesterday() throws ParseException { + LocalDateTime parse = GitTimeParser.parse("yesterday"); + + LocalDateTime now = SystemReader.getInstance().civilNow(); + assertEquals(Period.between(parse.toLocalDate(), now.toLocalDate()), + Period.ofDays(1)); + } + + @Test + public void never() throws ParseException { + LocalDateTime parse = GitTimeParser.parse("never"); + assertEquals(LocalDateTime.MAX, parse); + } + + @Test + public void now_pointInTime() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 15:35:00 +0100"); + + LocalDateTime parsedNow = GitTimeParser.parse("now", aTime); + + assertEquals(aTime, parsedNow); + } + + @Test + public void now_systemTime() throws ParseException { + LocalDateTime firstNow = GitTimeParser.parse("now"); + assertEquals(SystemReader.getInstance().civilNow(), firstNow); + mockSystemReader.tick(10); + LocalDateTime secondNow = GitTimeParser.parse("now"); + assertTrue(secondNow.isAfter(firstNow)); + } + + @Test + public void weeksAgo() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 15:35:00 +0100"); + + LocalDateTime parse = GitTimeParser.parse("2 weeks ago", aTime); + assertEquals(asLocalDateTime("2007-02-07 15:35:00 +0100"), parse); + } + + @Test + public void daysAndWeeksAgo() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 15:35:00 +0100"); + + LocalDateTime twoWeeksAgoActual = GitTimeParser.parse("2 weeks ago", + aTime); + + LocalDateTime twoWeeksAgoExpected = asLocalDateTime( + "2007-02-07 15:35:00 +0100"); + assertEquals(twoWeeksAgoExpected, twoWeeksAgoActual); + + LocalDateTime combinedWhitespace = GitTimeParser + .parse("3 days 2 weeks ago", aTime); + LocalDateTime combinedWhitespaceExpected = asLocalDateTime( + "2007-02-04 15:35:00 +0100"); + assertEquals(combinedWhitespaceExpected, combinedWhitespace); + + LocalDateTime combinedDots = GitTimeParser.parse("3.day.2.week.ago", + aTime); + LocalDateTime combinedDotsExpected = asLocalDateTime( + "2007-02-04 15:35:00 +0100"); + assertEquals(combinedDotsExpected, combinedDots); + } + + @Test + public void hoursAgo() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 17:35:00 +0100"); + + LocalDateTime twoHoursAgoActual = GitTimeParser.parse("2 hours ago", + aTime); + + LocalDateTime twoHoursAgoExpected = asLocalDateTime( + "2007-02-21 15:35:00 +0100"); + assertEquals(twoHoursAgoExpected, twoHoursAgoActual); + } + + @Test + public void hoursAgo_acrossDay() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 00:35:00 +0100"); + + LocalDateTime twoHoursAgoActual = GitTimeParser.parse("2 hours ago", + aTime); + + LocalDateTime twoHoursAgoExpected = asLocalDateTime( + "2007-02-20 22:35:00 +0100"); + assertEquals(twoHoursAgoExpected, twoHoursAgoActual); + } + + @Test + public void minutesHoursAgoCombined() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-04 15:35:00 +0100"); + + LocalDateTime combinedWhitespace = GitTimeParser + .parse("3 hours 2 minutes ago", aTime); + LocalDateTime combinedWhitespaceExpected = asLocalDateTime( + "2007-02-04 12:33:00 +0100"); + assertEquals(combinedWhitespaceExpected, combinedWhitespace); + + LocalDateTime combinedDots = GitTimeParser + .parse("3.hours.2.minutes.ago", aTime); + LocalDateTime combinedDotsExpected = asLocalDateTime( + "2007-02-04 12:33:00 +0100"); + assertEquals(combinedDotsExpected, combinedDots); + } + + @Test + public void minutesAgo() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 17:35:10 +0100"); + + LocalDateTime twoMinutesAgo = GitTimeParser.parse("2 minutes ago", + aTime); + + LocalDateTime twoMinutesAgoExpected = asLocalDateTime( + "2007-02-21 17:33:10 +0100"); + assertEquals(twoMinutesAgoExpected, twoMinutesAgo); + } + + @Test + public void minutesAgo_acrossDay() throws ParseException { + LocalDateTime aTime = asLocalDateTime("2007-02-21 00:35:10 +0100"); + + LocalDateTime minutesAgoActual = GitTimeParser.parse("40 minutes ago", + aTime); + + LocalDateTime minutesAgoExpected = asLocalDateTime( + "2007-02-20 23:55:10 +0100"); + assertEquals(minutesAgoExpected, minutesAgoActual); + } + + @Test + public void iso() throws ParseException { + String dateStr = "2007-02-21 15:35:00 +0100"; + + LocalDateTime actual = GitTimeParser.parse(dateStr); + + LocalDateTime expected = asLocalDateTime(dateStr); + assertEquals(expected, actual); + } + + @Test + public void rfc() throws ParseException { + String dateStr = "Wed, 21 Feb 2007 15:35:00 +0100"; + + LocalDateTime actual = GitTimeParser.parse(dateStr); + + LocalDateTime expected = asLocalDateTime(dateStr, + "EEE, dd MMM yyyy HH:mm:ss Z"); + assertEquals(expected, actual); + } + + @Test + public void shortFmt() throws ParseException { + assertParsing("2007-02-21", "yyyy-MM-dd"); + } + + @Test + public void shortWithDots() throws ParseException { + assertParsing("2007.02.21", "yyyy.MM.dd"); + } + + @Test + public void shortWithSlash() throws ParseException { + assertParsing("02/21/2007", "MM/dd/yyyy"); + } + + @Test + public void shortWithDotsReverse() throws ParseException { + assertParsing("21.02.2007", "dd.MM.yyyy"); + } + + @Test + public void defaultFmt() throws ParseException { + assertParsing("Wed Feb 21 15:35:00 2007 +0100", + "EEE MMM dd HH:mm:ss yyyy Z"); + } + + @Test + public void local() throws ParseException { + assertParsing("Wed Feb 21 15:35:00 2007", "EEE MMM dd HH:mm:ss yyyy"); + } + + private static void assertParsing(String dateStr, String format) + throws ParseException { + LocalDateTime actual = GitTimeParser.parse(dateStr); + + LocalDateTime expected = asLocalDateTime(dateStr, format); + assertEquals(expected, actual); + } + + private static LocalDateTime asLocalDateTime(String dateStr) { + return asLocalDateTime(dateStr, "yyyy-MM-dd HH:mm:ss Z"); + } + + private static LocalDateTime asLocalDateTime(String dateStr, + String pattern) { + DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern); + TemporalAccessor ta = fmt + .withZone(SystemReader.getInstance().getTimeZoneId()) + .withLocale(SystemReader.getInstance().getLocale()) + .parse(dateStr); + return ta.isSupported(ChronoField.HOUR_OF_DAY) ? LocalDateTime.from(ta) + : LocalDate.from(ta).atStartOfDay(); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_ParsePersonIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_ParsePersonIdentTest.java index 355bbba..6d23db8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_ParsePersonIdentTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_ParsePersonIdentTest.java
@@ -10,10 +10,13 @@ package org.eclipse.jgit.util; +import static java.time.Instant.EPOCH; +import static java.time.ZoneOffset.UTC; import static org.junit.Assert.assertEquals; -import java.util.Date; -import java.util.TimeZone; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; import org.eclipse.jgit.lib.PersonIdent; import org.junit.Test; @@ -22,8 +25,8 @@ public class RawParseUtils_ParsePersonIdentTest { @Test public void testParsePersonIdent_legalCases() { - final Date when = new Date(1234567890000L); - final TimeZone tz = TimeZone.getTimeZone("GMT-7"); + Instant when = Instant.ofEpochMilli(1234567890000L); + ZoneId tz = ZoneOffset.ofHours(-7); assertPersonIdent("Me <me@example.com> 1234567890 -0700", new PersonIdent("Me", "me@example.com", when, tz)); @@ -50,8 +53,8 @@ public void testParsePersonIdent_legalCases() { @Test public void testParsePersonIdent_fuzzyCases() { - final Date when = new Date(1234567890000L); - final TimeZone tz = TimeZone.getTimeZone("GMT-7"); + Instant when = Instant.ofEpochMilli(1234567890000L); + ZoneId tz = ZoneOffset.ofHours(-7); assertPersonIdent( "A U Thor <author@example.com>, C O. Miter <comiter@example.com> 1234567890 -0700", @@ -64,8 +67,8 @@ public void testParsePersonIdent_fuzzyCases() { @Test public void testParsePersonIdent_incompleteCases() { - final Date when = new Date(1234567890000L); - final TimeZone tz = TimeZone.getTimeZone("GMT-7"); + Instant when = Instant.ofEpochMilli(1234567890000L); + ZoneId tz = ZoneOffset.ofHours(-7); assertPersonIdent("Me <> 1234567890 -0700", new PersonIdent("Me", "", when, tz)); @@ -76,26 +79,26 @@ public void testParsePersonIdent_incompleteCases() { assertPersonIdent(" <> 1234567890 -0700", new PersonIdent("", "", when, tz)); - assertPersonIdent("<>", new PersonIdent("", "", 0, 0)); + assertPersonIdent("<>", new PersonIdent("", "", EPOCH, UTC)); - assertPersonIdent(" <>", new PersonIdent("", "", 0, 0)); + assertPersonIdent(" <>", new PersonIdent("", "", EPOCH, UTC)); assertPersonIdent("<me@example.com>", new PersonIdent("", - "me@example.com", 0, 0)); + "me@example.com", EPOCH, UTC)); assertPersonIdent(" <me@example.com>", new PersonIdent("", - "me@example.com", 0, 0)); + "me@example.com", EPOCH, UTC)); - assertPersonIdent("Me <>", new PersonIdent("Me", "", 0, 0)); + assertPersonIdent("Me <>", new PersonIdent("Me", "", EPOCH, UTC)); assertPersonIdent("Me <me@example.com>", new PersonIdent("Me", - "me@example.com", 0, 0)); + "me@example.com", EPOCH, UTC)); assertPersonIdent("Me <me@example.com> 1234567890", new PersonIdent( - "Me", "me@example.com", 0, 0)); + "Me", "me@example.com", EPOCH, UTC)); assertPersonIdent("Me <me@example.com> 1234567890 ", new PersonIdent( - "Me", "me@example.com", 0, 0)); + "Me", "me@example.com", EPOCH, UTC)); } @Test @@ -104,6 +107,21 @@ public void testParsePersonIdent_malformedCases() { assertPersonIdent("Me <me@example.com 1234567890 -0700", null); } + @Test + public void testParsePersonIdent_badTz() { + PersonIdent tooBig = RawParseUtils + .parsePersonIdent("Me <me@example.com> 1234567890 +8315"); + assertEquals(tooBig.getZoneOffset().getTotalSeconds(), 0); + + PersonIdent tooSmall = RawParseUtils + .parsePersonIdent("Me <me@example.com> 1234567890 -8315"); + assertEquals(tooSmall.getZoneOffset().getTotalSeconds(), 0); + + PersonIdent notATime = RawParseUtils + .parsePersonIdent("Me <me@example.com> 1234567890 -0370"); + assertEquals(notATime.getZoneOffset().getTotalSeconds(), 0); + } + private static void assertPersonIdent(String line, PersonIdent expected) { PersonIdent actual = RawParseUtils.parsePersonIdent(line); assertEquals(expected, actual);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java index 214bbca..a927d8d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RelativeDateFormatterTest.java
@@ -16,7 +16,7 @@ import static org.eclipse.jgit.util.RelativeDateFormatter.YEAR_IN_MILLIS; import static org.junit.Assert.assertEquals; -import java.util.Date; +import java.time.Instant; import org.eclipse.jgit.junit.MockSystemReader; import org.junit.After; @@ -37,9 +37,9 @@ public void tearDown() { private static void assertFormat(long ageFromNow, long timeUnit, String expectedFormat) { - Date d = new Date(SystemReader.getInstance().getCurrentTime() - - ageFromNow * timeUnit); - String s = RelativeDateFormatter.format(d); + long millis = ageFromNow * timeUnit; + Instant aTime = SystemReader.getInstance().now().minusMillis(millis); + String s = RelativeDateFormatter.format(aTime); assertEquals(expectedFormat, s); }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java index 015da16..9a1c710 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java
@@ -12,6 +12,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -172,4 +173,22 @@ public void testCommonPrefix() { assertEquals("foo bar ", StringUtils.commonPrefix("foo bar 42", "foo bar 24")); } + + @Test + public void testTrim() { + assertEquals("a", StringUtils.trim("a", '/')); + assertEquals("aaaa", StringUtils.trim("aaaa", '/')); + assertEquals("aaa", StringUtils.trim("/aaa", '/')); + assertEquals("aaa", StringUtils.trim("aaa/", '/')); + assertEquals("aaa", StringUtils.trim("/aaa/", '/')); + assertEquals("aa/aa", StringUtils.trim("/aa/aa/", '/')); + assertEquals("aa/aa", StringUtils.trim("aa/aa", '/')); + + assertEquals("", StringUtils.trim("", '/')); + assertEquals("", StringUtils.trim("/", '/')); + assertEquals("", StringUtils.trim("//", '/')); + assertEquals("", StringUtils.trim("///", '/')); + + assertNull(StringUtils.trim(null, '/')); + } }
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF index 04bda44..e0b049c 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -4,14 +4,14 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ui Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.jgit.awtui;version="7.0.0" -Import-Package: org.eclipse.jgit.errors;version="[7.0.0,7.1.0)", - org.eclipse.jgit.lib;version="[7.0.0,7.1.0)", - org.eclipse.jgit.nls;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revplot;version="[7.0.0,7.1.0)", - org.eclipse.jgit.revwalk;version="[7.0.0,7.1.0)", - org.eclipse.jgit.transport;version="[7.0.0,7.1.0)", - org.eclipse.jgit.util;version="[7.0.0,7.1.0)" +Export-Package: org.eclipse.jgit.awtui;version="7.3.0" +Import-Package: org.eclipse.jgit.errors;version="[7.3.0,7.4.0)", + org.eclipse.jgit.lib;version="[7.3.0,7.4.0)", + org.eclipse.jgit.nls;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revplot;version="[7.3.0,7.4.0)", + org.eclipse.jgit.revwalk;version="[7.3.0,7.4.0)", + org.eclipse.jgit.transport;version="[7.3.0,7.4.0)", + org.eclipse.jgit.util;version="[7.3.0,7.4.0)"
diff --git a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF index 8170fc6..66617ca 100644 --- a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit.ui - Sources Bundle-SymbolicName: org.eclipse.jgit.ui.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ui;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ui;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index 6d1e267..3d8d2a1 100644 --- a/org.eclipse.jgit.ui/pom.xml +++ b/org.eclipse.jgit.ui/pom.xml
@@ -19,7 +19,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index caefce3..877a488 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,10 +1,62 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <component id="org.eclipse.jgit" version="2"> - <resource path="src/org/eclipse/jgit/lib/GpgSignatureVerifier.java" type="org.eclipse.jgit.lib.GpgSignatureVerifier"> - <filter id="404000815"> + <resource path="src/org/eclipse/jgit/lib/RefDatabase.java" type="org.eclipse.jgit.lib.RefDatabase"> + <filter id="336695337"> <message_arguments> - <message_argument value="org.eclipse.jgit.lib.GpgSignatureVerifier"/> - <message_argument value="verify(GpgConfig, byte[], byte[])"/> + <message_argument value="org.eclipse.jgit.lib.RefDatabase"/> + <message_argument value="getReflogReader(Ref)"/> + </message_arguments> + </filter> + <filter id="336695337"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.RefDatabase"/> + <message_argument value="getReflogReader(String)"/> + </message_arguments> + </filter> + </resource> + <resource path="src/org/eclipse/jgit/lib/TypedConfigGetter.java" type="org.eclipse.jgit.lib.TypedConfigGetter"> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/> + <message_argument value="getBoolean(Config, String, String, String, Boolean)"/> + </message_arguments> + </filter> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/> + <message_argument value="getInt(Config, String, String, String, Integer)"/> + </message_arguments> + </filter> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/> + <message_argument value="getIntInRange(Config, String, String, String, Integer, Integer, Integer)"/> + </message_arguments> + </filter> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/> + <message_argument value="getIntInRange(Config, String, String, String, int, int, Integer)"/> + </message_arguments> + </filter> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/> + <message_argument value="getLong(Config, String, String, String, Long)"/> + </message_arguments> + </filter> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.lib.TypedConfigGetter"/> + <message_argument value="getTimeUnit(Config, String, String, String, Long, TimeUnit)"/> + </message_arguments> + </filter> + </resource> + <resource path="src/org/eclipse/jgit/revwalk/RevWalk.java" type="org.eclipse.jgit.revwalk.RevWalk"> + <filter id="1142947843"> + <message_arguments> + <message_argument value="6.10.1"/> + <message_argument value="isMergedIntoAnyCommit(RevCommit, Collection<RevCommit>)"/> </message_arguments> </filter> </resource>
diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs index c4dc76f..ef3d8ec 100644 --- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
@@ -40,7 +40,7 @@ org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=error org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled -org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 2cdfa99..5f851ec 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 7.0.0.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/org.eclipse.jgit.internal.util.CleanupService.xml Eclipse-ExtensibleAPI: true -Export-Package: org.eclipse.jgit.annotations;version="7.0.0", - org.eclipse.jgit.api;version="7.0.0"; +Export-Package: org.eclipse.jgit.annotations;version="7.3.0", + org.eclipse.jgit.api;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.notes, org.eclipse.jgit.dircache, @@ -25,72 +25,77 @@ org.eclipse.jgit.revwalk.filter, org.eclipse.jgit.blame, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="7.0.0"; + org.eclipse.jgit.api.errors;version="7.3.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.errors", - org.eclipse.jgit.attributes;version="7.0.0"; + org.eclipse.jgit.attributes;version="7.3.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk", - org.eclipse.jgit.blame;version="7.0.0"; + org.eclipse.jgit.blame;version="7.3.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, - org.eclipse.jgit.treewalk.filter, - org.eclipse.jgit.diff", - org.eclipse.jgit.diff;version="7.0.0"; + org.eclipse.jgit.blame.cache, + org.eclipse.jgit.diff, + org.eclipse.jgit.treewalk.filter", + org.eclipse.jgit.blame.cache;version="7.3.0"; + uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.diff;version="7.3.0"; uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.attributes, org.eclipse.jgit.revwalk, org.eclipse.jgit.patch, + org.eclipse.jgit.attributes, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk, org.eclipse.jgit.util", - org.eclipse.jgit.dircache;version="7.0.0"; + org.eclipse.jgit.dircache;version="7.3.0"; uses:="org.eclipse.jgit.events, org.eclipse.jgit.lib, org.eclipse.jgit.attributes, org.eclipse.jgit.treewalk, org.eclipse.jgit.util", - org.eclipse.jgit.errors;version="7.0.0"; + org.eclipse.jgit.errors;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.dircache, - org.eclipse.jgit.lib, - org.eclipse.jgit.internal.storage.pack", - org.eclipse.jgit.events;version="7.0.0"; + org.eclipse.jgit.lib", + org.eclipse.jgit.events;version="7.3.0"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.fnmatch;version="7.0.0", - org.eclipse.jgit.gitrepo;version="7.0.0"; + org.eclipse.jgit.fnmatch;version="7.3.0", + org.eclipse.jgit.gitrepo;version="7.3.0"; uses:="org.xml.sax.helpers, org.eclipse.jgit.api, + org.eclipse.jgit.api.errors, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.xml.sax", - org.eclipse.jgit.gitrepo.internal;version="7.0.0";x-internal:=true, - org.eclipse.jgit.hooks;version="7.0.0";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.ignore;version="7.0.0", - org.eclipse.jgit.ignore.internal;version="7.0.0"; + org.eclipse.jgit.gitrepo.internal;version="7.3.0";x-internal:=true, + org.eclipse.jgit.hooks;version="7.3.0"; + uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.util", + org.eclipse.jgit.ignore;version="7.3.0", + org.eclipse.jgit.ignore.internal;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal;version="7.0.0"; + org.eclipse.jgit.internal;version="7.3.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.diff;version="7.0.0"; + org.eclipse.jgit.internal.diff;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.diffmergetool;version="7.0.0"; + org.eclipse.jgit.internal.diffmergetool;version="7.3.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.pgm.test, org.eclipse.jgit.pgm, org.eclipse.egit.ui", - org.eclipse.jgit.internal.fsck;version="7.0.0"; + org.eclipse.jgit.internal.fsck;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.revwalk;version="7.0.0"; + org.eclipse.jgit.internal.revwalk;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.commitgraph;version="7.0.0"; + org.eclipse.jgit.internal.storage.commitgraph;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.dfs;version="7.0.0"; + org.eclipse.jgit.internal.storage.dfs;version="7.3.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.http.server, org.eclipse.jgit.http.test, org.eclipse.jgit.lfs.test", - org.eclipse.jgit.internal.storage.file;version="7.0.0"; + org.eclipse.jgit.internal.storage.file;version="7.3.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, org.eclipse.jgit.junit.http, @@ -99,41 +104,43 @@ org.eclipse.jgit.pgm, org.eclipse.jgit.pgm.test, org.eclipse.jgit.ssh.apache", - org.eclipse.jgit.internal.storage.io;version="7.0.0"; + org.eclipse.jgit.internal.storage.io;version="7.3.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.memory;version="7.0.0"; + org.eclipse.jgit.internal.storage.memory;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.pack;version="7.0.0"; + org.eclipse.jgit.internal.storage.midx;version="7.3.0";x-internal:=true, + org.eclipse.jgit.internal.storage.pack;version="7.3.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.reftable;version="7.0.0"; + org.eclipse.jgit.internal.storage.reftable;version="7.3.0"; x-friends:="org.eclipse.jgit.http.test, org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.submodule;version="7.0.0";x-internal:=true, - org.eclipse.jgit.internal.transport.connectivity;version="7.0.0"; + org.eclipse.jgit.internal.submodule;version="7.3.0";x-internal:=true, + org.eclipse.jgit.internal.transport.connectivity;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.http;version="7.0.0"; + org.eclipse.jgit.internal.transport.http;version="7.3.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.parser;version="7.0.0"; + org.eclipse.jgit.internal.transport.parser;version="7.3.0"; x-friends:="org.eclipse.jgit.http.server, org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.ssh;version="7.0.0"; + org.eclipse.jgit.internal.transport.ssh;version="7.3.0"; x-friends:="org.eclipse.jgit.ssh.apache, org.eclipse.jgit.ssh.jsch, org.eclipse.jgit.test", - org.eclipse.jgit.internal.util;version="7.0.0"; - x-friends:=" org.eclipse.jgit.junit", - org.eclipse.jgit.lib;version="7.0.0"; + org.eclipse.jgit.internal.util;version="7.3.0"; + x-friends:="org.eclipse.jgit.junit", + org.eclipse.jgit.lib;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util.sha1, org.eclipse.jgit.dircache, org.eclipse.jgit.revwalk, org.eclipse.jgit.internal.storage.file, + org.eclipse.jgit.api, org.eclipse.jgit.attributes, org.eclipse.jgit.events, com.googlecode.javaewah, @@ -142,12 +149,12 @@ org.eclipse.jgit.util, org.eclipse.jgit.submodule, org.eclipse.jgit.util.time", - org.eclipse.jgit.lib.internal;version="7.0.0"; + org.eclipse.jgit.lib.internal;version="7.3.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.pgm, org.eclipse.egit.ui", - org.eclipse.jgit.logging;version="7.0.0", - org.eclipse.jgit.merge;version="7.0.0"; + org.eclipse.jgit.logging;version="7.3.0", + org.eclipse.jgit.merge;version="7.3.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -156,67 +163,69 @@ org.eclipse.jgit.util, org.eclipse.jgit.api, org.eclipse.jgit.attributes", - org.eclipse.jgit.nls;version="7.0.0", - org.eclipse.jgit.notes;version="7.0.0"; + org.eclipse.jgit.nls;version="7.3.0", + org.eclipse.jgit.notes;version="7.3.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="7.0.0"; + org.eclipse.jgit.patch;version="7.3.0"; uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.revwalk, org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="7.0.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.revwalk", - org.eclipse.jgit.revwalk;version="7.0.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.diff, - org.eclipse.jgit.treewalk.filter, - org.eclipse.jgit.revwalk.filter, - org.eclipse.jgit.treewalk", - org.eclipse.jgit.revwalk.filter;version="7.0.0"; + org.eclipse.jgit.revplot;version="7.3.0"; uses:="org.eclipse.jgit.revwalk, - org.eclipse.jgit.lib, - org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="7.0.0"; + org.eclipse.jgit.lib", + org.eclipse.jgit.revwalk;version="7.3.0"; uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="7.0.0"; - uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="7.0.0"; - uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.revwalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk, + org.eclipse.jgit.internal.storage.commitgraph", + org.eclipse.jgit.revwalk.filter;version="7.3.0"; + uses:="org.eclipse.jgit.revwalk, + org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.transport;version="7.0.0"; + org.eclipse.jgit.storage.file;version="7.3.0"; + uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.util", + org.eclipse.jgit.storage.pack;version="7.3.0"; + uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.submodule;version="7.3.0"; + uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.treewalk.filter, + org.eclipse.jgit.diff, + org.eclipse.jgit.treewalk, + org.eclipse.jgit.util", + org.eclipse.jgit.transport;version="7.3.0"; uses:="javax.crypto, + org.eclipse.jgit.hooks, org.eclipse.jgit.util.io, org.eclipse.jgit.lib, - org.eclipse.jgit.revwalk, org.eclipse.jgit.transport.http, - org.eclipse.jgit.internal.storage.file, + org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk, org.eclipse.jgit.util, org.eclipse.jgit.internal.storage.pack, org.eclipse.jgit.transport.resolver, org.eclipse.jgit.storage.pack, org.eclipse.jgit.errors", - org.eclipse.jgit.transport.http;version="7.0.0"; + org.eclipse.jgit.transport.http;version="7.3.0"; uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="7.0.0"; + org.eclipse.jgit.transport.resolver;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.lib", - org.eclipse.jgit.treewalk;version="7.0.0"; + org.eclipse.jgit.treewalk;version="7.3.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.attributes, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util", - org.eclipse.jgit.treewalk.filter;version="7.0.0"; + org.eclipse.jgit.treewalk.filter;version="7.3.0"; uses:="org.eclipse.jgit.treewalk", - org.eclipse.jgit.util;version="7.0.0"; + org.eclipse.jgit.util;version="7.3.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.hooks, org.eclipse.jgit.revwalk, @@ -229,18 +238,18 @@ org.eclipse.jgit.treewalk, javax.net.ssl, org.eclipse.jgit.util.time", - org.eclipse.jgit.util.io;version="7.0.0"; + org.eclipse.jgit.util.io;version="7.3.0"; uses:="org.eclipse.jgit.attributes, org.eclipse.jgit.lib, org.eclipse.jgit.treewalk", - org.eclipse.jgit.util.sha1;version="7.0.0", - org.eclipse.jgit.util.time;version="7.0.0" + org.eclipse.jgit.util.sha1;version="7.3.0", + org.eclipse.jgit.util.time;version="7.3.0" Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", javax.crypto, javax.management, javax.net.ssl, - org.apache.commons.codec.digest;version="1.15.0", + org.apache.commons.codec.digest;version="[1.15.0,2.0.0)", org.slf4j;version="[1.7.0,3.0.0)", org.xml.sax, org.xml.sax.helpers
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index 7531018..a9e669b 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.0.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit;version="7.0.0.qualifier";roots="." +Bundle-Version: 7.3.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit;version="7.3.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 9397674..c65a440 100644 --- a/org.eclipse.jgit/pom.xml +++ b/org.eclipse.jgit/pom.xml
@@ -20,7 +20,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit</artifactId> @@ -49,7 +49,6 @@ <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> - <version>1.16.0</version> </dependency> </dependencies>
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 19c9008..27270a1 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -64,8 +64,6 @@ binaryHunkInvalidLength=Binary hunk, line {0}: input corrupt; expected length byte, got 0x{1} binaryHunkLineTooShort=Binary hunk, line {0}: input ended prematurely binaryHunkMissingNewline=Binary hunk, line {0}: input line not terminated by newline -bitmapAccessErrorForPackfile=Error whilst trying to access bitmap file for {} -bitmapFailedToGet=Failed to get bitmap index file {} bitmapMissingObject=Bitmap at {0} is missing {1}. bitmapsMustBePrepared=Bitmaps must be prepared before they may be written. bitmapUseNoopNoListener=Use NOOP instance for no listener @@ -78,6 +76,7 @@ buildingBitmaps=Building bitmaps cachedPacksPreventsIndexCreation=Using cached packs prevents index creation cachedPacksPreventsListingObjects=Using cached packs prevents listing objects +cacheRegionAllOrNoneNull=expected all null or none: {0}, {1} cannotAccessLastModifiedForSafeDeletion=Unable to access lastModifiedTime of file {0}, skip deletion since we cannot safely avoid race condition cannotBeCombined=Cannot be combined. cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included. @@ -267,6 +266,7 @@ deletingNotSupported=Deleting {0} not supported. depthMustBeAt1=Depth must be >= 1 depthWithUnshallow=Depth and unshallow can\'t be used together +deprecatedTrustFolderStat=Option core.trustFolderStat is deprecated, replace it by core.trustStat. destinationIsNotAWildcard=Destination is not a wildcard. detachedHeadDetected=HEAD is detached diffToolNotGivenError=No diff tool provided and no defaults configured. @@ -285,6 +285,9 @@ downloadCancelled=Download cancelled downloadCancelledDuringIndexing=Download cancelled during indexing duplicateAdvertisementsOf=duplicate advertisements of {0} +duplicateCacheTablesGiven=Duplicate cache tables given +duplicatePackExtensionsForCacheTables=Duplicate pack extension {0} in cache tables +duplicatePackExtensionsSet=Attempting to configure duplicate pack extensions: {0}.{1}.{2} contains {3} duplicateRef=Duplicate ref: {0} duplicateRefAttribute=Duplicate ref attribute: {0} duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0} @@ -461,6 +464,7 @@ invalidTimeUnitValue2=Invalid time unit value: {0}.{1}={2} invalidTimeUnitValue3=Invalid time unit value: {0}.{1}.{2}={3} invalidTreeZeroLengthName=Cannot append a tree entry with zero-length name +invalidTrustStat=core.trustStat must not be set to TrustStat.INHERIT, falling back to TrustStat.ALWAYS. invalidURL=Invalid URL {0} invalidWildcards=Invalid wildcards {0} invalidRefSpec=Invalid refspec {0} @@ -499,7 +503,7 @@ mergeStrategyAlreadyExistsAsDefault=Merge strategy "{0}" already exists as a default strategy mergeStrategyDoesNotSupportHeads=merge strategy {0} does not support {1} heads to be merged into HEAD mergeUsingStrategyResultedInDescription=Merge of revisions {0} with base {1} using strategy {2} resulted in: {3}. {4} -mergeRecursiveConflictsWhenMergingCommonAncestors=Multiple common ancestors were found and merging them resulted in a conflict: {0}, {1} +mergeRecursiveConflictsWhenMergingCommonAncestors=Multiple common ancestors were found and merging them resulted in a conflict: {0}, {1}\nFailing paths: {2} mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b {2} found:\n count {3}" mergeToolNotGivenError=No merge tool provided and no defaults configured. mergeToolNullError=Parameter for merge tool cannot be null. @@ -524,6 +528,8 @@ month=month months=months monthsAgo={0} months ago +multiPackIndexUnexpectedSize=MultiPack index: expected %d bytes but out has %d bytes +multiPackIndexWritingCancelled=Multipack index writing was canceled multipleMergeBasesFor=Multiple merge bases for:\n {0}\n {1} found:\n {2}\n {3} nameMustNotBeNullOrEmpty=Ref name must not be null or empty. need2Arguments=Need 2 arguments @@ -539,6 +545,8 @@ noMergeHeadSpecified=No merge head specified nonBareLinkFilesNotSupported=Link files are not supported with nonbare repos nonCommitToHeads=Cannot point a branch to a non-commit object +noPackExtConfigurationGiven=No PackExt configuration given +noPackExtGivenForConfiguration=No PackExt given for configuration noPathAttributesFound=No Attributes found for {0}. noSuchRef=no such ref noSuchRefKnown=no such ref: {0} @@ -571,7 +579,6 @@ oldIdMustNotBeNull=Expected old ID must not be null onlyOneFetchSupported=Only one fetch supported onlyOneOperationCallPerConnectionIsSupported=Only one operation call per connection is supported. -onlyOpenPgpSupportedForSigning=OpenPGP is the only supported signing option with JGit at this time (gpg.format must be set to openpgp). openFilesMustBeAtLeast1=Open files must be >= 1 openingConnection=Opening connection operationCanceled=Operation {0} was canceled @@ -593,6 +600,8 @@ packingCancelledDuringObjectsWriting=Packing cancelled during objects writing packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2} packRefs=Pack refs +packRefsFailed=Packing refs failed +packRefsSuccessful=Packed refs successfully packSizeNotSetYet=Pack size not yet set since it has not yet been received packTooLargeForIndexVersion1=Pack too large for index version 1 packWasDeleted=Pack file {0} was deleted, removing it from pack list @@ -609,6 +618,7 @@ personIdentEmailNonNull=E-mail address of PersonIdent must not be null. personIdentNameNonNull=Name of PersonIdent must not be null. postCommitHookFailed=Execution of post-commit hook failed: {0}. +precedenceTrustConfig=Both core.trustFolderStat and core.trustStat are set, ignoring trustFolderStat since trustStat takes precedence. Remove core.trustFolderStat from your configuration. prefixRemote=remote: problemWithResolvingPushRefSpecsLocally=Problem with resolving push ref specs locally: {0} progressMonUploading=Uploading {0} @@ -636,8 +646,6 @@ readerIsRequired=Reader is required readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0} readLastModifiedFailed=Reading lastModified of {0} failed -readPipeIsNotAllowed=FS.readPipe() isn't allowed for command ''{0}''. Working directory: ''{1}''. -readPipeIsNotAllowedRequiredPermission=FS.readPipe() isn't allowed for command ''{0}''. Working directory: ''{1}''. Required permission: {2}. readTimedOut=Read timed out after {0} ms receivePackObjectTooLarge1=Object too large, rejecting the pack. Max object size limit is {0} bytes. receivePackObjectTooLarge2=Object too large ({0} bytes), rejecting the pack. Max object size limit is {1} bytes. @@ -718,6 +726,8 @@ shutdownCleanup=Cleanup {} during JVM shutdown shutdownCleanupFailed=Cleanup during JVM shutdown failed shutdownCleanupListenerFailed=Cleanup of {0} during JVM shutdown failed +signatureServiceConflict={0} conflict for type {1}. Already registered is {2}; additional factory {3} is ignored. +signatureTypeUnknown=No signer for {0} signatures. Use another signature type for git config gpg.format, or do not sign. signatureVerificationError=Signature verification failed signatureVerificationUnavailable=No signature verifier registered signedTagMessageNoLf=A non-empty message of a signed tag must end in LF. @@ -803,6 +813,7 @@ tSizeMustBeGreaterOrEqual1=tSize must be >= 1 unableToCheckConnectivity=Unable to check connectivity. unableToCreateNewObject=Unable to create new object: {0} +unableToReadFullArray=Unable to read an array with {0} elements from the stream unableToReadFullInt=Unable to read a full int from the stream unableToReadPackfile=Unable to read packfile {0} unableToRemovePath=Unable to remove path ''{0}'' @@ -829,6 +840,7 @@ unknownObjectInIndex=unknown object {0} found in index but not in pack file unknownObjectType=Unknown object type {0}. unknownObjectType2=unknown +unknownPackExtension=Unknown pack extension: {0}.{1}.{2}={3} unknownPositionEncoding=Unknown position encoding %s unknownRefStorageFormat=Unknown ref storage format "{0}" unknownRepositoryFormat=Unknown repository format
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java index c895dc9..b4d1cab 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -1,6 +1,6 @@ /* * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> - * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> and others + * Copyright (C) 2010, 2025 Stefan Lay <stefan.lay@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 @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; +import java.text.MessageFormat; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -59,8 +60,15 @@ public class AddCommand extends GitCommand<DirCache> { private WorkingTreeIterator workingTreeIterator; + // Update only known index entries, don't add new ones. If there's no file + // for an index entry, remove it: stage deletions. private boolean update = false; + // If TRUE, also stage deletions, otherwise only update and add index + // entries. + // If not set explicitly + private Boolean all; + // This defaults to true because it's what JGit has been doing // traditionally. The C git default would be false. private boolean renormalize = true; @@ -82,6 +90,17 @@ public AddCommand(Repository repo) { * A directory name (e.g. <code>dir</code> to add <code>dir/file1</code> and * <code>dir/file2</code>) can also be given to add all files in the * directory, recursively. Fileglobs (e.g. *.c) are not yet supported. + * </p> + * <p> + * If a pattern {@code "."} is added, all changes in the git repository's + * working tree will be added. + * </p> + * <p> + * File patterns are required unless {@code isUpdate() == true} or + * {@link #setAll(boolean)} is called. If so and no file patterns are given, + * all changes will be added (i.e., a file pattern of {@code "."} is + * implied). + * </p> * * @param filepattern * repository-relative path of file/directory to add (with @@ -113,15 +132,41 @@ public AddCommand setWorkingTreeIterator(WorkingTreeIterator f) { * Executes the {@code Add} command. Each instance of this class should only * be used for one invocation of the command. Don't call this method twice * on an instance. + * </p> + * + * @throws JGitInternalException + * on errors, but also if {@code isUpdate() == true} _and_ + * {@link #setAll(boolean)} had been called + * @throws NoFilepatternException + * if no file patterns are given if {@code isUpdate() == false} + * and {@link #setAll(boolean)} was not called */ @Override public DirCache call() throws GitAPIException, NoFilepatternException { - - if (filepatterns.isEmpty()) - throw new NoFilepatternException(JGitText.get().atLeastOnePatternIsRequired); checkCallable(); + + if (update && all != null) { + throw new JGitInternalException(MessageFormat.format( + JGitText.get().illegalCombinationOfArguments, + "--update", "--all/--no-all")); //$NON-NLS-1$ //$NON-NLS-2$ + } + boolean addAll; + if (filepatterns.isEmpty()) { + if (update || all != null) { + addAll = true; + } else { + throw new NoFilepatternException( + JGitText.get().atLeastOnePatternIsRequired); + } + } else { + addAll = filepatterns.contains("."); //$NON-NLS-1$ + if (all == null && !update) { + all = Boolean.TRUE; + } + } + boolean stageDeletions = update || (all != null && all.booleanValue()); + DirCache dc = null; - boolean addAll = filepatterns.contains("."); //$NON-NLS-1$ try (ObjectInserter inserter = repo.newObjectInserter(); NameConflictTreeWalk tw = new NameConflictTreeWalk(repo)) { @@ -181,7 +226,8 @@ public DirCache call() throws GitAPIException, NoFilepatternException { if (f == null) { // working tree file does not exist if (entry != null - && (!update || GITLINK == entry.getFileMode())) { + && (!stageDeletions + || GITLINK == entry.getFileMode())) { builder.add(entry); } continue; @@ -252,7 +298,8 @@ public DirCache call() throws GitAPIException, NoFilepatternException { } /** - * Set whether to only match against already tracked files + * Set whether to only match against already tracked files. If + * {@code update == true}, re-sets a previous {@link #setAll(boolean)}. * * @param update * If set to true, the command only matches {@code filepattern} @@ -314,4 +361,32 @@ public AddCommand setRenormalize(boolean renormalize) { public boolean isRenormalize() { return renormalize; } + + /** + * Defines whether the command will use '--all' mode: update existing index + * entries, add new entries, and remove index entries for which there is no + * file. (In other words: also stage deletions.) + * <p> + * The setting is independent of {@link #setUpdate(boolean)}. + * </p> + * + * @param all + * whether to enable '--all' mode + * @return {@code this} + * @since 7.2 + */ + public AddCommand setAll(boolean all) { + this.all = Boolean.valueOf(all); + return this; + } + + /** + * Tells whether '--all' has been set for this command. + * + * @return {@code true} if it was set; {@code false} otherwise + * @since 7.2 + */ + public boolean isAll() { + return all != null && all.booleanValue(); + } }
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 c133219..32c242f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -644,24 +644,6 @@ public CheckoutCommand setOrphan(boolean orphan) { /** * Specify to force the ref update in case of a branch switch. * - * @param force - * if <code>true</code> and the branch with the given name - * already exists, the start-point of an existing branch will be - * set to a new start-point; if false, the existing branch will - * not be changed - * @return this instance - * @deprecated this method was badly named comparing its semantics to native - * git's checkout --force option, use - * {@link #setForceRefUpdate(boolean)} instead - */ - @Deprecated - public CheckoutCommand setForce(boolean force) { - return setForceRefUpdate(force); - } - - /** - * Specify to force the ref update in case of a branch switch. - * * In releases prior to 5.2 this method was called setForce() but this name * was misunderstood to implement native git's --force option, which is not * true.
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 3e034f1..4a536b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -67,6 +67,8 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private boolean bare; + private boolean relativePaths; + private FS fs; private String remote = Constants.DEFAULT_REMOTE_NAME; @@ -264,6 +266,7 @@ void verifyDirectories(URIish u) { private Repository init() throws GitAPIException { InitCommand command = Git.init(); command.setBare(bare); + command.setRelativeDirs(relativePaths); if (fs != null) { command.setFs(fs); } @@ -555,6 +558,20 @@ public CloneCommand setBare(boolean bare) throws IllegalStateException { } /** + * Set whether the cloned repository shall use relative paths for GIT_DIR + * and GIT_WORK_TREE + * + * @param relativePaths + * if true, use relative paths for GIT_DIR and GIT_WORK_TREE + * @return this instance + * @since 7.2 + */ + public CloneCommand setRelativePaths(boolean relativePaths) { + this.relativePaths = relativePaths; + return this; + } + + /** * Set the file system abstraction to be used for repositories created by * this command. *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java index a1a2cc0..a7d409c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -51,9 +51,6 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.GpgConfig; -import org.eclipse.jgit.lib.GpgConfig.GpgFormat; -import org.eclipse.jgit.lib.GpgObjectSigner; -import org.eclipse.jgit.lib.GpgSigner; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.PersonIdent; @@ -62,6 +59,8 @@ import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; +import org.eclipse.jgit.lib.Signer; +import org.eclipse.jgit.lib.Signers; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevTag; @@ -129,7 +128,7 @@ public class CommitCommand extends GitCommand<RevCommit> { private String signingKey; - private GpgSigner gpgSigner; + private Signer signer; private GpgConfig gpgConfig; @@ -319,30 +318,22 @@ private void checkIfEmpty(RevWalk rw, ObjectId headId, ObjectId indexTreeId) } } - private void sign(CommitBuilder commit) throws ServiceUnavailableException, - CanceledException, UnsupportedSigningFormatException { - if (gpgSigner == null) { - gpgSigner = GpgSigner.getDefault(); - if (gpgSigner == null) { - throw new ServiceUnavailableException( - JGitText.get().signingServiceUnavailable); + private void sign(CommitBuilder commit) + throws CanceledException, IOException, + UnsupportedSigningFormatException { + if (signer == null) { + signer = Signers.get(gpgConfig.getKeyFormat()); + if (signer == null) { + throw new UnsupportedSigningFormatException(MessageFormat + .format(JGitText.get().signatureTypeUnknown, + gpgConfig.getKeyFormat().toConfigValue())); } } if (signingKey == null) { signingKey = gpgConfig.getSigningKey(); } - if (gpgSigner instanceof GpgObjectSigner) { - ((GpgObjectSigner) gpgSigner).signObject(commit, - signingKey, committer, credentialsProvider, - gpgConfig); - } else { - if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) { - throw new UnsupportedSigningFormatException(JGitText - .get().onlyOpenPgpSupportedForSigning); - } - gpgSigner.sign(commit, signingKey, committer, - credentialsProvider); - } + signer.signObject(repo, gpgConfig, commit, committer, signingKey, + credentialsProvider); } private void updateRef(RepositoryState state, ObjectId headId, @@ -1097,22 +1088,22 @@ public CommitCommand setSign(Boolean sign) { } /** - * Sets the {@link GpgSigner} to use if the commit is to be signed. + * Sets the {@link Signer} to use if the commit is to be signed. * * @param signer * to use; if {@code null}, the default signer will be used * @return {@code this} - * @since 5.11 + * @since 7.0 */ - public CommitCommand setGpgSigner(GpgSigner signer) { + public CommitCommand setSigner(Signer signer) { checkCallable(); - this.gpgSigner = signer; + this.signer = signer; return this; } /** * Sets an external {@link GpgConfig} to use. Whether it will be used is at - * the discretion of the {@link #setGpgSigner(GpgSigner)}. + * the discretion of the {@link #setSigner(Signer)}. * * @param config * to set; if {@code null}, the config will be loaded from the
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 805a886..d252628 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -15,11 +15,11 @@ import java.io.IOException; import java.text.MessageFormat; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Optional; @@ -76,6 +76,11 @@ public class DescribeCommand extends GitCommand<String> { private List<FileNameMatcher> matchers = new ArrayList<>(); /** + * Pattern matchers to be applied to tags for exclusion. + */ + private List<FileNameMatcher> excludeMatchers = new ArrayList<>(); + + /** * Whether to use all refs in the refs/ namespace */ private boolean useAll; @@ -263,6 +268,27 @@ public DescribeCommand setMatch(String... patterns) throws InvalidPatternExcepti return this; } + /** + * Sets one or more {@code glob(7)} patterns that tags must not match to be + * considered. If multiple patterns are provided, they will all be applied. + * + * @param patterns + * the {@code glob(7)} pattern or patterns + * @return {@code this} + * @throws org.eclipse.jgit.errors.InvalidPatternException + * if the pattern passed in was invalid. + * @see <a href= + * "https://www.kernel.org/pub/software/scm/git/docs/git-describe.html" + * >Git documentation about describe</a> + * @since 7.2 + */ + public DescribeCommand setExclude(String... patterns) throws InvalidPatternException { + for (String p : patterns) { + excludeMatchers.add(new FileNameMatcher(p, null)); + } + return this; + } + private final Comparator<Ref> TAG_TIE_BREAKER = new Comparator<>() { @Override @@ -274,25 +300,28 @@ public int compare(Ref o1, Ref o2) { } } - private Date tagDate(Ref tag) throws IOException { + private Instant tagDate(Ref tag) throws IOException { RevTag t = w.parseTag(tag.getObjectId()); w.parseBody(t); - return t.getTaggerIdent().getWhen(); + return t.getTaggerIdent().getWhenAsInstant(); } }; private Optional<Ref> getBestMatch(List<Ref> tags) { if (tags == null || tags.isEmpty()) { return Optional.empty(); - } else if (matchers.isEmpty()) { + } else if (matchers.isEmpty() && excludeMatchers.isEmpty()) { Collections.sort(tags, TAG_TIE_BREAKER); return Optional.of(tags.get(0)); - } else { + } + + Stream<Ref> matchingTags; + if (!matchers.isEmpty()) { // Find the first tag that matches in the stream of all tags // filtered by matchers ordered by tie break order - Stream<Ref> matchingTags = Stream.empty(); + matchingTags = Stream.empty(); for (FileNameMatcher matcher : matchers) { - Stream<Ref> m = tags.stream().filter( + Stream<Ref> m = tags.stream().filter( // tag -> { matcher.append(formatRefName(tag.getName())); boolean result = matcher.isMatch(); @@ -301,8 +330,22 @@ private Optional<Ref> getBestMatch(List<Ref> tags) { }); matchingTags = Stream.of(matchingTags, m).flatMap(i -> i); } - return matchingTags.sorted(TAG_TIE_BREAKER).findFirst(); + } else { + // If there are no matchers, there are only excluders + // Assume all tags match for now before applying excluders + matchingTags = tags.stream(); } + + for (FileNameMatcher matcher : excludeMatchers) { + matchingTags = matchingTags.filter( // + tag -> { + matcher.append(formatRefName(tag.getName())); + boolean result = matcher.isMatch(); + matcher.reset(); + return !result; + }); + } + return matchingTags.sorted(TAG_TIE_BREAKER).findFirst(); } private ObjectId getObjectIdFromRef(Ref r) throws JGitInternalException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java index 0713c38..f24127b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -124,7 +124,7 @@ private FetchRecurseSubmodulesMode getRecurseMode(String path) { FetchRecurseSubmodulesMode mode = repo.getConfig().getEnum( FetchRecurseSubmodulesMode.values(), ConfigConstants.CONFIG_SUBMODULE_SECTION, path, - ConfigConstants.CONFIG_KEY_FETCH_RECURSE_SUBMODULES, null); + ConfigConstants.CONFIG_KEY_FETCH_RECURSE_SUBMODULES); if (mode != null) { return mode; } @@ -132,7 +132,7 @@ private FetchRecurseSubmodulesMode getRecurseMode(String path) { // Fall back to fetch.recurseSubmodules, if set mode = repo.getConfig().getEnum(FetchRecurseSubmodulesMode.values(), ConfigConstants.CONFIG_FETCH_SECTION, null, - ConfigConstants.CONFIG_KEY_RECURSE_SUBMODULES, null); + ConfigConstants.CONFIG_KEY_RECURSE_SUBMODULES); if (mode != null) { return mode; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java index 88d7e91..f6935e1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java
@@ -12,6 +12,7 @@ import java.io.IOException; import java.text.MessageFormat; import java.text.ParseException; +import java.time.Instant; import java.util.Date; import java.util.Properties; import java.util.concurrent.ExecutionException; @@ -59,7 +60,7 @@ public class GarbageCollectCommand extends GitCommand<Properties> { private ProgressMonitor monitor; - private Date expire; + private Instant expire; private PackConfig pconfig; @@ -98,8 +99,29 @@ public GarbageCollectCommand setProgressMonitor(ProgressMonitor monitor) { * @param expire * minimal age of objects to be pruned. * @return this instance + * @deprecated use {@link #setExpire(Instant)} instead */ + @Deprecated(since = "7.2") public GarbageCollectCommand setExpire(Date expire) { + if (expire != null) { + this.expire = expire.toInstant(); + } + return this; + } + + /** + * During gc() or prune() each unreferenced, loose object which has been + * created or modified after <code>expire</code> will not be pruned. Only + * older objects may be pruned. If set to null then every object is a + * candidate for pruning. Use {@link org.eclipse.jgit.util.GitTimeParser} to + * parse time formats used by git gc. + * + * @param expire + * minimal age of objects to be pruned. + * @return this instance + * @since 7.2 + */ + public GarbageCollectCommand setExpire(Instant expire) { this.expire = expire; return this; } @@ -108,8 +130,8 @@ public GarbageCollectCommand setExpire(Date expire) { * Whether to use aggressive mode or not. If set to true JGit behaves more * similar to native git's "git gc --aggressive". If set to * <code>true</code> compressed objects found in old packs are not reused - * but every object is compressed again. Configuration variables - * pack.window and pack.depth are set to 250 for this GC. + * but every object is compressed again. Configuration variables pack.window + * and pack.depth are set to 250 for this GC. * * @since 3.6 * @param aggressive
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java index 3dc53ec..5bc035a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -714,6 +714,16 @@ public GarbageCollectCommand gc() { } /** + * Return a command object to execute a {@code PackRefs} command + * + * @return a {@link org.eclipse.jgit.api.PackRefsCommand} + * @since 7.1 + */ + public PackRefsCommand packRefs() { + return new PackRefsCommand(repo); + } + + /** * Return a command object to find human-readable names of revisions. * * @return a {@link org.eclipse.jgit.api.NameRevCommand}.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java index 240290f..1da71aa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
@@ -19,6 +19,7 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; @@ -44,6 +45,8 @@ public class InitCommand implements Callable<Git> { private String initialBranch; + private boolean relativePaths; + /** * {@inheritDoc} * <p> @@ -100,7 +103,11 @@ public Git call() throws GitAPIException { : initialBranch); Repository repository = builder.build(); if (!repository.getObjectDatabase().exists()) - repository.create(bare); + if (repository instanceof FileRepository) { + ((FileRepository) repository).create(bare, relativePaths); + } else { + repository.create(bare); + } return new Git(repository, true); } catch (IOException | ConfigInvalidException e) { throw new JGitInternalException(e.getMessage(), e); @@ -214,4 +221,18 @@ public InitCommand setInitialBranch(String branch) this.initialBranch = branch; return this; } + + /** + * * Set whether the repository shall use relative paths for GIT_DIR and + * GIT_WORK_TREE + * + * @param relativePaths + * if true, use relative paths for GIT_DIR and GIT_WORK_TREE + * @return {@code this} + * @since 7.2 + */ + public InitCommand setRelativeDirs(boolean relativePaths) { + this.relativePaths = relativePaths; + return this; + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java new file mode 100644 index 0000000..29a69c5 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PackRefsCommand.java
@@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License 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.api; + +import java.io.IOException; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.lib.Repository; + +/** + * Optimize storage of references. + * + * @since 7.1 + */ +public class PackRefsCommand extends GitCommand<String> { + private ProgressMonitor monitor; + + private boolean all; + + /** + * Creates a new {@link PackRefsCommand} instance with default values. + * + * @param repo + * the repository this command will be used on + */ + public PackRefsCommand(Repository repo) { + super(repo); + this.monitor = NullProgressMonitor.INSTANCE; + } + + /** + * Set progress monitor + * + * @param monitor + * a progress monitor + * @return this instance + */ + public PackRefsCommand setProgressMonitor(ProgressMonitor monitor) { + this.monitor = monitor; + return this; + } + + /** + * Specify whether to pack all the references. + * + * @param all + * if <code>true</code> all the loose refs will be packed + * @return this instance + */ + public PackRefsCommand setAll(boolean all) { + this.all = all; + return this; + } + + /** + * Whether to pack all the references + * + * @return whether to pack all the references + */ + public boolean isAll() { + return all; + } + + @Override + public String call() throws GitAPIException { + checkCallable(); + try { + repo.getRefDatabase().packRefs(monitor, this); + return JGitText.get().packRefsSuccessful; + } catch (IOException e) { + throw new JGitInternalException(JGitText.get().packRefsFailed, e); + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java index 83ae0fc..4b2cee4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -533,9 +533,9 @@ public static BranchRebaseMode getRebaseMode(String branchName, Config config) { BranchRebaseMode mode = config.getEnum(BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, - branchName, ConfigConstants.CONFIG_KEY_REBASE, null); + branchName, ConfigConstants.CONFIG_KEY_REBASE); if (mode == null) { - mode = config.getEnum(BranchRebaseMode.values(), + mode = config.getEnum( ConfigConstants.CONFIG_PULL_SECTION, null, ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE); } @@ -549,7 +549,7 @@ private FastForwardMode getFastForwardMode() { Config config = repo.getConfig(); Merge ffMode = config.getEnum(Merge.values(), ConfigConstants.CONFIG_PULL_SECTION, null, - ConfigConstants.CONFIG_KEY_FF, null); + ConfigConstants.CONFIG_KEY_FF); return ffMode != null ? FastForwardMode.valueOf(ffMode) : null; } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index 858bd96..3ae7a6c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -18,6 +18,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.text.MessageFormat; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -1835,23 +1837,26 @@ PersonIdent parseAuthor(byte[] raw) { // the time is saved as <seconds since 1970> <timezone offset> int timeStart = 0; - if (time.startsWith("@")) //$NON-NLS-1$ + if (time.startsWith("@")) { //$NON-NLS-1$ timeStart = 1; - else + } else { timeStart = 0; - long when = Long - .parseLong(time.substring(timeStart, time.indexOf(' '))) * 1000; + } + Instant when = Instant.ofEpochSecond( + Long.parseLong(time.substring(timeStart, time.indexOf(' ')))); String tzOffsetString = time.substring(time.indexOf(' ') + 1); int multiplier = -1; - if (tzOffsetString.charAt(0) == '+') + if (tzOffsetString.charAt(0) == '+') { multiplier = 1; + } int hours = Integer.parseInt(tzOffsetString.substring(1, 3)); int minutes = Integer.parseInt(tzOffsetString.substring(3, 5)); // this is in format (+/-)HHMM (hours and minutes) - // we need to convert into minutes - int tz = (hours * 60 + minutes) * multiplier; - if (name != null && email != null) + ZoneOffset tz = ZoneOffset.ofHoursMinutes(hours * multiplier, + minutes * multiplier); + if (name != null && email != null) { return new PersonIdent(name, email, when, tz); + } return null; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java index dead274..a149649 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ReflogCommand.java
@@ -68,7 +68,7 @@ public Collection<ReflogEntry> call() throws GitAPIException, checkCallable(); try { - ReflogReader reader = repo.getReflogReader(ref); + ReflogReader reader = repo.getRefDatabase().getReflogReader(ref); if (reader == null) throw new RefNotFoundException(MessageFormat.format( JGitText.get().refNotResolved, ref));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java index 553fc2e..ad553f0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
@@ -49,18 +49,6 @@ protected RemoteRemoveCommand(Repository repo) { /** * The name of the remote to remove. * - * @param name - * a remote name - * @deprecated use {@link #setRemoteName} instead - */ - @Deprecated - public void setName(String name) { - this.remoteName = name; - } - - /** - * The name of the remote to remove. - * * @param remoteName * a remote name * @return {@code this}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java index e3d0186..68ddce3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
@@ -71,18 +71,6 @@ protected RemoteSetUrlCommand(Repository repo) { /** * The name of the remote to change the URL for. * - * @param name - * a remote name - * @deprecated use {@link #setRemoteName} instead - */ - @Deprecated - public void setName(String name) { - this.remoteName = name; - } - - /** - * The name of the remote to change the URL for. - * * @param remoteName * a remote remoteName * @return {@code this} @@ -96,18 +84,6 @@ public RemoteSetUrlCommand setRemoteName(String remoteName) { /** * The new URL for the remote. * - * @param uri - * an URL for the remote - * @deprecated use {@link #setRemoteUri} instead - */ - @Deprecated - public void setUri(URIish uri) { - this.remoteUri = uri; - } - - /** - * The new URL for the remote. - * * @param remoteUri * an URL for the remote * @return {@code this} @@ -121,23 +97,6 @@ public RemoteSetUrlCommand setRemoteUri(URIish remoteUri) { /** * Whether to change the push URL of the remote instead of the fetch URL. * - * @param push - * <code>true</code> to set the push url, <code>false</code> to - * set the fetch url - * @deprecated use {@link #setUriType} instead - */ - @Deprecated - public void setPush(boolean push) { - if (push) { - setUriType(UriType.PUSH); - } else { - setUriType(UriType.FETCH); - } - } - - /** - * Whether to change the push URL of the remote instead of the fetch URL. - * * @param type * the <code>UriType</code> value to set * @return {@code this}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java index 855c3b1..6643c83 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> and others + * Copyright (C) 2010, 2024 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 @@ -143,8 +143,8 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException, merger.setCommitNames(new String[] { "BASE", ourName, revertName }); //$NON-NLS-1$ - String shortMessage = "Revert \"" + srcCommit.getShortMessage() //$NON-NLS-1$ - + "\""; //$NON-NLS-1$ + String shortMessage = "Revert \"" //$NON-NLS-1$ + + srcCommit.getFirstMessageLine() + '"'; String newMessage = shortMessage + "\n\n" //$NON-NLS-1$ + "This reverts commit " + srcCommit.getId().getName() //$NON-NLS-1$ + ".\n"; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java index e415728..b0b715e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -263,18 +263,6 @@ public ObjectId call() throws GitAPIException, /** * Whether to restore the index state * - * @param applyIndex - * true (default) if the command should restore the index state - * @deprecated use {@link #setRestoreIndex} instead - */ - @Deprecated - public void setApplyIndex(boolean applyIndex) { - this.restoreIndex = applyIndex; - } - - /** - * Whether to restore the index state - * * @param restoreIndex * true (default) if the command should restore the index state * @return {@code this} @@ -319,19 +307,6 @@ public StashApplyCommand setContentMergeStrategy( /** * Whether the command should restore untracked files * - * @param applyUntracked - * true (default) if the command should restore untracked files - * @since 3.4 - * @deprecated use {@link #setRestoreUntracked} instead - */ - @Deprecated - public void setApplyUntracked(boolean applyUntracked) { - this.restoreUntracked = applyUntracked; - } - - /** - * Whether the command should restore untracked files - * * @param restoreUntracked * true (default) if the command should restore untracked files * @return {@code this}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java index 23fbe01..2dba0ef 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
@@ -165,7 +165,8 @@ public ObjectId call() throws GitAPIException { List<ReflogEntry> entries; try { - ReflogReader reader = repo.getReflogReader(R_STASH); + ReflogReader reader = repo.getRefDatabase() + .getReflogReader(R_STASH); if (reader == null) { throw new RefNotFoundException(MessageFormat .format(JGitText.get().refNotResolved, stashRef));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java index 8fb5d60..5105dfc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -176,8 +176,9 @@ public Repository call() throws GitAPIException { CloneCommand clone = Git.cloneRepository(); configure(clone); clone.setDirectory(moduleDirectory); - clone.setGitDir(new File(new File(repo.getDirectory(), - Constants.MODULES), path)); + clone.setGitDir(new File( + new File(repo.getCommonDirectory(), Constants.MODULES), path)); + clone.setRelativePaths(true); clone.setURI(resolvedUri); if (monitor != null) clone.setProgressMonitor(monitor);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java index df73164..5e4b2ee 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -28,6 +28,7 @@ import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.internal.storage.file.LockFile; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; @@ -39,6 +40,7 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.submodule.SubmoduleWalk; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.util.FileUtils; /** * A class used to execute a submodule update command. @@ -62,6 +64,8 @@ public class SubmoduleUpdateCommand extends private boolean fetch = false; + private boolean clonedRestored; + /** * <p> * Constructor for SubmoduleUpdateCommand. @@ -116,25 +120,77 @@ public SubmoduleUpdateCommand addPath(String path) { return this; } + private static boolean submoduleExists(File gitDir) { + if (gitDir != null && gitDir.isDirectory()) { + File[] files = gitDir.listFiles(); + return files != null && files.length != 0; + } + return false; + } + + private static void restoreSubmodule(File gitDir, File workingTree) + throws IOException { + LockFile dotGitLock = new LockFile( + new File(workingTree, Constants.DOT_GIT)); + if (dotGitLock.lock()) { + String content = Constants.GITDIR + + getRelativePath(gitDir, workingTree); + dotGitLock.write(Constants.encode(content)); + dotGitLock.commit(); + } + } + + private static String getRelativePath(File gitDir, File workingTree) { + File relPath; + try { + relPath = workingTree.toPath().relativize(gitDir.toPath()) + .toFile(); + } catch (IllegalArgumentException e) { + relPath = gitDir; + } + return FileUtils.pathToString(relPath); + } + + private String determineUpdateMode(String mode) { + if (clonedRestored) { + return ConfigConstants.CONFIG_KEY_CHECKOUT; + } + return mode; + } + private Repository getOrCloneSubmodule(SubmoduleWalk generator, String url) throws IOException, GitAPIException { Repository repository = generator.getRepository(); + boolean restored = false; + boolean cloned = false; if (repository == null) { - if (callback != null) { - callback.cloningSubmodule(generator.getPath()); + File gitDir = new File( + new File(repo.getCommonDirectory(), Constants.MODULES), + generator.getPath()); + if (submoduleExists(gitDir)) { + restoreSubmodule(gitDir, generator.getDirectory()); + restored = true; + clonedRestored = true; + repository = generator.getRepository(); + } else { + if (callback != null) { + callback.cloningSubmodule(generator.getPath()); + } + CloneCommand clone = Git.cloneRepository(); + configure(clone); + clone.setURI(url); + clone.setDirectory(generator.getDirectory()); + clone.setGitDir(gitDir); + clone.setRelativePaths(true); + if (monitor != null) { + clone.setProgressMonitor(monitor); + } + repository = clone.call().getRepository(); + cloned = true; + clonedRestored = true; } - CloneCommand clone = Git.cloneRepository(); - configure(clone); - clone.setURI(url); - clone.setDirectory(generator.getDirectory()); - clone.setGitDir( - new File(new File(repo.getDirectory(), Constants.MODULES), - generator.getPath())); - if (monitor != null) { - clone.setProgressMonitor(monitor); - } - repository = clone.call().getRepository(); - } else if (this.fetch) { + } + if ((this.fetch || restored) && !cloned) { if (fetchCallback != null) { fetchCallback.fetchingSubmodule(generator.getPath()); } @@ -171,15 +227,17 @@ public Collection<String> call() throws InvalidConfigurationException, continue; // Skip submodules not registered in parent repository's config String url = generator.getConfigUrl(); - if (url == null) + if (url == null) { continue; - + } + clonedRestored = false; try (Repository submoduleRepo = getOrCloneSubmodule(generator, url); RevWalk walk = new RevWalk(submoduleRepo)) { RevCommit commit = walk .parseCommit(generator.getObjectId()); - String update = generator.getConfigUpdate(); + String update = determineUpdateMode( + generator.getConfigUpdate()); if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) { MergeCommand merge = new MergeCommand(submoduleRepo); merge.include(commit);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java index 3edaf5e..cc8589f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
@@ -18,14 +18,11 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; -import org.eclipse.jgit.api.errors.ServiceUnavailableException; import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.GpgConfig; import org.eclipse.jgit.lib.GpgConfig.GpgFormat; -import org.eclipse.jgit.lib.GpgObjectSigner; -import org.eclipse.jgit.lib.GpgSigner; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.PersonIdent; @@ -33,6 +30,8 @@ import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.Signer; +import org.eclipse.jgit.lib.Signers; import org.eclipse.jgit.lib.TagBuilder; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; @@ -79,7 +78,7 @@ public class TagCommand extends GitCommand<Ref> { private GpgConfig gpgConfig; - private GpgObjectSigner gpgSigner; + private Signer signer; private CredentialsProvider credentialsProvider; @@ -133,9 +132,9 @@ public Ref call() throws GitAPIException, ConcurrentRefUpdateException, newTag.setTagger(tagger); newTag.setObjectId(id); - if (gpgSigner != null) { - gpgSigner.signObject(newTag, signingKey, tagger, - credentialsProvider, gpgConfig); + if (signer != null) { + signer.signObject(repo, gpgConfig, newTag, tagger, signingKey, + credentialsProvider); } // write the tag object @@ -196,15 +195,12 @@ private Ref updateTagRef(ObjectId tagId, RevWalk revWalk, * * @throws InvalidTagNameException * if the tag name is null or invalid - * @throws ServiceUnavailableException - * if the tag should be signed but no signer can be found * @throws UnsupportedSigningFormatException * if the tag should be signed but {@code gpg.format} is not * {@link GpgFormat#OPENPGP} */ private void processOptions() - throws InvalidTagNameException, ServiceUnavailableException, - UnsupportedSigningFormatException { + throws InvalidTagNameException, UnsupportedSigningFormatException { if (name == null || !Repository.isValidRefName(Constants.R_TAGS + name)) { throw new InvalidTagNameException( @@ -230,16 +226,15 @@ private void processOptions() doSign = gpgConfig.isSignAnnotated(); } if (doSign) { - if (signingKey == null) { - signingKey = gpgConfig.getSigningKey(); - } - if (gpgSigner == null) { - GpgSigner signer = GpgSigner.getDefault(); - if (!(signer instanceof GpgObjectSigner)) { - throw new ServiceUnavailableException( - JGitText.get().signingServiceUnavailable); + if (signer == null) { + signer = Signers.get(gpgConfig.getKeyFormat()); + if (signer == null) { + throw new UnsupportedSigningFormatException( + MessageFormat.format( + JGitText.get().signatureTypeUnknown, + gpgConfig.getKeyFormat() + .toConfigValue())); } - gpgSigner = (GpgObjectSigner) signer; } // The message of a signed tag must end in a newline because // the signature will be appended. @@ -326,22 +321,22 @@ public TagCommand setSigned(boolean signed) { } /** - * Sets the {@link GpgSigner} to use if the commit is to be signed. + * Sets the {@link Signer} to use if the commit is to be signed. * * @param signer * to use; if {@code null}, the default signer will be used * @return {@code this} - * @since 5.11 + * @since 7.0 */ - public TagCommand setGpgSigner(GpgObjectSigner signer) { + public TagCommand setSigner(Signer signer) { checkCallable(); - this.gpgSigner = signer; + this.signer = signer; return this; } /** * Sets an external {@link GpgConfig} to use. Whether it will be used is at - * the discretion of the {@link #setGpgSigner(GpgObjectSigner)}. + * the discretion of the {@link #setSigner(Signer)}. * * @param config * to set; if {@code null}, the config will be loaded from the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java index 21cddf7..f5f4b06 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerificationResult.java
@@ -9,7 +9,7 @@ */ package org.eclipse.jgit.api; -import org.eclipse.jgit.lib.GpgSignatureVerifier; +import org.eclipse.jgit.lib.SignatureVerifier; import org.eclipse.jgit.revwalk.RevObject; /** @@ -34,8 +34,9 @@ public interface VerificationResult { * Retrieves the signature verification result. * * @return the result, or {@code null} if none was computed + * @since 7.0 */ - GpgSignatureVerifier.SignatureVerification getVerification(); + SignatureVerifier.SignatureVerification getVerification(); /** * Retrieves the git object of which the signature was verified.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java index 6a2a44e..487ff04 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/VerifySignatureCommand.java
@@ -25,11 +25,10 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.GpgConfig; -import org.eclipse.jgit.lib.GpgSignatureVerifier; -import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification; -import org.eclipse.jgit.lib.GpgSignatureVerifierFactory; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.SignatureVerifiers; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; @@ -65,12 +64,8 @@ public enum VerifyMode { private VerifyMode mode = VerifyMode.ANY; - private GpgSignatureVerifier verifier; - private GpgConfig config; - private boolean ownVerifier; - /** * Creates a new {@link VerifySignatureCommand} for the given {@link Repository}. * @@ -140,22 +135,7 @@ public VerifySignatureCommand setMode(@NonNull VerifyMode mode) { } /** - * Sets the {@link GpgSignatureVerifier} to use. - * - * @param verifier - * the {@link GpgSignatureVerifier} to use, or {@code null} to - * use the default verifier - * @return {@code this} - */ - public VerifySignatureCommand setVerifier(GpgSignatureVerifier verifier) { - checkCallable(); - this.verifier = verifier; - return this; - } - - /** - * Sets an external {@link GpgConfig} to use. Whether it will be used it at - * the discretion of the {@link #setVerifier(GpgSignatureVerifier)}. + * Sets an external {@link GpgConfig} to use. * * @param config * to set; if {@code null}, the config will be loaded from the @@ -170,16 +150,6 @@ public VerifySignatureCommand setGpgConfig(GpgConfig config) { } /** - * Retrieves the currently set {@link GpgSignatureVerifier}. Can be used - * after a successful {@link #call()} to get the verifier that was used. - * - * @return the {@link GpgSignatureVerifier} - */ - public GpgSignatureVerifier getVerifier() { - return verifier; - } - - /** * {@link Repository#resolve(String) Resolves} all names added to the * command to git objects and verifies their signature. Non-existing objects * are ignored. @@ -193,9 +163,6 @@ public GpgSignatureVerifier getVerifier() { * * @return a map of the given names to the corresponding * {@link VerificationResult}, excluding ignored or skipped objects. - * @throws ServiceUnavailableException - * if no {@link GpgSignatureVerifier} was set and no - * {@link GpgSignatureVerifierFactory} is available * @throws WrongObjectTypeException * if a name resolves to an object of a type not allowed by the * {@link #setMode(VerifyMode)} mode @@ -207,16 +174,6 @@ public Map<String, VerificationResult> call() checkCallable(); setCallable(false); Map<String, VerificationResult> result = new HashMap<>(); - if (verifier == null) { - GpgSignatureVerifierFactory factory = GpgSignatureVerifierFactory - .getDefault(); - if (factory == null) { - throw new ServiceUnavailableException( - JGitText.get().signatureVerificationUnavailable); - } - verifier = factory.getVerifier(); - ownVerifier = true; - } if (config == null) { config = new GpgConfig(repo.getConfig()); } @@ -239,10 +196,6 @@ public Map<String, VerificationResult> call() } catch (IOException e) { throw new JGitInternalException( JGitText.get().signatureVerificationError, e); - } finally { - if (ownVerifier) { - verifier.clear(); - } } return result; } @@ -258,8 +211,8 @@ private VerificationResult verifyOne(RevObject object) } if (type == Constants.OBJ_COMMIT || type == Constants.OBJ_TAG) { try { - GpgSignatureVerifier.SignatureVerification verification = verifier - .verifySignature(object, config); + SignatureVerification verification = SignatureVerifiers + .verify(repo, config, object); if (verification == null) { // Not signed return null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java index fe3e22a..9c4d870 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
@@ -9,6 +9,8 @@ */ package org.eclipse.jgit.attributes; +import org.eclipse.jgit.annotations.Nullable; + /** * Represents an attribute. * <p> @@ -139,6 +141,7 @@ public State getState() { * * @return the attribute value (may be <code>null</code>) */ + @Nullable public String getValue() { return value; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java index 77967df..2d499ca 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
@@ -28,6 +28,8 @@ import org.eclipse.jgit.blame.Candidate.HeadCandidate; import org.eclipse.jgit.blame.Candidate.ReverseCandidate; import org.eclipse.jgit.blame.ReverseWalk.ReverseCommit; +import org.eclipse.jgit.blame.cache.BlameCache; +import org.eclipse.jgit.blame.cache.CacheRegion; import org.eclipse.jgit.diff.DiffAlgorithm; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; @@ -129,8 +131,19 @@ public class BlameGenerator implements AutoCloseable { /** Blame is currently assigned to this source. */ private Candidate outCandidate; + private Region outRegion; + private final BlameCache blameCache; + + /** + * Blame in reverse order needs the source lines, but we don't have them in + * the cache. We need to ignore the cache in that case. + */ + private boolean useCache = true; + + private final Stats stats = new Stats(); + /** * Create a blame generator for the repository and path (relative to * repository) @@ -142,6 +155,25 @@ public class BlameGenerator implements AutoCloseable { * repository). */ public BlameGenerator(Repository repository, String path) { + this(repository, path, null); + } + + /** + * Create a blame generator for the repository and path (relative to + * repository) + * + * @param repository + * repository to access revision data from. + * @param path + * initial path of the file to start scanning (relative to the + * repository). + * @param blameCache + * previously calculated blames. This generator will *not* + * populate it, just consume it. + * @since 7.2 + */ + public BlameGenerator(Repository repository, String path, + @Nullable BlameCache blameCache) { this.repository = repository; this.resultPath = PathFilter.create(path); @@ -150,6 +182,7 @@ public BlameGenerator(Repository repository, String path) { initRevPool(false); remaining = -1; + this.blameCache = blameCache; } private void initRevPool(boolean reverse) { @@ -159,10 +192,12 @@ private void initRevPool(boolean reverse) { if (revPool != null) revPool.close(); - if (reverse) + if (reverse) { + useCache = false; revPool = new ReverseWalk(getRepository()); - else + } else { revPool = new RevWalk(getRepository()); + } SEEN = revPool.newFlag("SEEN"); //$NON-NLS-1$ reader = revPool.getObjectReader(); @@ -245,6 +280,31 @@ public RenameDetector getRenameDetector() { } /** + * Stats about this generator + * + * @return the stats of this generator + * @since 7.2 + */ + public Stats getStats() { + return stats; + } + + /** + * Enable/disable the use of cache (if present). Enabled by default. + * <p> + * If caller need source line numbers, the generator cannot use the cache + * (source lines are not there). Use this method to disable the cache in + * that case. + * + * @param useCache + * should this generator use the cache. + * @since 7.2 + */ + public void setUseCache(boolean useCache) { + this.useCache = useCache; + } + + /** * Push a candidate blob onto the generator's traversal stack. * <p> * Candidates should be pushed in history order from oldest-to-newest. @@ -591,6 +651,20 @@ public boolean next() throws IOException { Candidate n = pop(); if (n == null) return done(); + stats.candidatesVisited += 1; + if (blameCache != null && useCache) { + List<CacheRegion> cachedBlame = blameCache.get(repository, + n.sourceCommit, n.sourcePath.getPath()); + if (cachedBlame != null) { + BlameRegionMerger rb = new BlameRegionMerger(repository, + revPool, cachedBlame); + Candidate fullyBlamed = rb.mergeCandidate(n); + if (fullyBlamed != null) { + stats.cacheHit = true; + return result(fullyBlamed); + } + } + } int pCnt = n.getParentCount(); if (pCnt == 1) { @@ -605,7 +679,7 @@ public boolean next() throws IOException { // Do not generate a tip of a reverse. The region // survives and should not appear to be deleted. - } else /* if (pCnt == 0) */{ + } else /* if (pCnt == 0) */ { // Root commit, with at least one surviving region. // Assign the remaining blame here. return result(n); @@ -846,8 +920,8 @@ private boolean processMerge(Candidate n) throws IOException { editList = new EditList(0); } else { p.loadText(reader); - editList = diffAlgorithm.diff(textComparator, - p.sourceText, n.sourceText); + editList = diffAlgorithm.diff(textComparator, p.sourceText, + n.sourceText); } if (editList.isEmpty()) { @@ -981,6 +1055,10 @@ public int getRenameScore() { /** * Get first line of the source data that has been blamed for the current * region + * <p> + * This value is not reliable when the generator is reusing cached values. + * Cache doesn't keep the source lines, the returned value is based on the + * result and can be off if the region moved in previous commits. * * @return first line of the source data that has been blamed for the * current region. This is line number of where the region was added @@ -994,6 +1072,10 @@ public int getSourceStart() { /** * Get one past the range of the source data that has been blamed for the * current region + * <p> + * This value is not reliable when the generator is reusing cached values. + * Cache doesn't keep the source lines, the returned value is based on the + * result and can be off if the region moved in previous commits. * * @return one past the range of the source data that has been blamed for * the current region. This is line number of where the region was @@ -1124,4 +1206,39 @@ private static boolean isRename(DiffEntry ent) { return ent.getChangeType() == ChangeType.RENAME || ent.getChangeType() == ChangeType.COPY; } + + /** + * Stats about the work done by the generator + * + * @since 7.2 + */ + public static class Stats { + + /** Candidates taken from the queue */ + private int candidatesVisited; + + private boolean cacheHit; + + /** + * Number of candidates taken from the queue + * <p> + * The generator could signal it's done without exhausting all + * candidates if there is no more remaining lines or the last visited + * candidate is found in the cache. + * + * @return number of candidates taken from the queue + */ + public int getCandidatesVisited() { + return candidatesVisited; + } + + /** + * The generator found a blamed version in the cache + * + * @return true if we used results from the cache + */ + public boolean isCacheHit() { + return cacheHit; + } + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameRegionMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameRegionMerger.java new file mode 100644 index 0000000..67bc6fb --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameRegionMerger.java
@@ -0,0 +1,158 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * 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.blame; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jgit.blame.cache.CacheRegion; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.filter.PathFilter; + +/** + * Translates an unblamed region into one or more blamed regions, using the + * fully blamed data from cache. + * <p> + * Blamed and unblamed regions are not symmetrical: An unblamed region is just a + * range of lines over the file. A blamed region is a Candidate (with the commit + * info) with a region inside (the range blamed). + */ +class BlameRegionMerger { + private final Repository repo; + + private final List<CacheRegion> cachedRegions; + + private final RevWalk rw; + + BlameRegionMerger(Repository repo, RevWalk rw, + List<CacheRegion> cachedRegions) { + this.repo = repo; + List<CacheRegion> sorted = new ArrayList<>(cachedRegions); + Collections.sort(sorted); + this.cachedRegions = sorted; + this.rw = rw; + } + + /** + * Return one or more candidates blaming all the regions of the "unblamed" + * incoming candidate. + * + * @param candidate + * a candidate with a list of unblamed regions + * @return A linked list of Candidates with their blamed regions, null if + * there was any error. + */ + Candidate mergeCandidate(Candidate candidate) { + List<Candidate> newCandidates = new ArrayList<>(); + Region r = candidate.regionList; + while (r != null) { + try { + newCandidates.addAll(mergeOneRegion(r)); + } catch (IOException e) { + return null; + } + r = r.next; + } + return asLinkedCandidate(newCandidates); + } + + // Visible for testing + List<Candidate> mergeOneRegion(Region region) throws IOException { + List<CacheRegion> overlaps = findOverlaps(region); + if (overlaps.isEmpty()) { + throw new IOException( + "Cached blame should cover all lines"); + } + /* + * Cached regions cover the whole file. We find first which ones overlap + * with our unblamed region. Then we take the overlapping portions with + * the corresponding blame. + */ + List<Candidate> candidates = new ArrayList<>(); + for (CacheRegion overlap : overlaps) { + Region blamedRegions = intersectRegions(region, overlap); + Candidate c = new Candidate(repo, parse(overlap.getSourceCommit()), + PathFilter.create(overlap.getSourcePath())); + c.regionList = blamedRegions; + candidates.add(c); + } + return candidates; + } + + // Visible for testing + List<CacheRegion> findOverlaps(Region unblamed) { + int unblamedStart = unblamed.sourceStart; + int unblamedEnd = unblamedStart + unblamed.length; + List<CacheRegion> overlapping = new ArrayList<>(); + for (CacheRegion blamed : cachedRegions) { + // End is not included + if (blamed.getEnd() <= unblamedStart) { + // Blamed region is completely before + continue; + } + + if (blamed.getStart() >= unblamedEnd) { + // Blamed region is completely after + // Blamed regions are sorted by start position, nothing will + // match anymore + break; + } + overlapping.add(blamed); + } + return overlapping; + } + + // Visible for testing + /** + * Calculate the intersection between a Region and a CacheRegion, adjusting + * the start if needed. + * <p> + * This should be called only if there is an overlap (filtering the cached + * regions with {@link #findOverlaps(Region)}), otherwise the result is + * meaningless. + * + * @param unblamed + * a region from the blame generator + * @param cached + * a cached region + * @return a new region with the intersection. + */ + static Region intersectRegions(Region unblamed, CacheRegion cached) { + int blamedStart = Math.max(cached.getStart(), unblamed.sourceStart); + int blamedEnd = Math.min(cached.getEnd(), + unblamed.sourceStart + unblamed.length); + int length = blamedEnd - blamedStart; + + // result start and source start should move together + int blameStartDelta = blamedStart - unblamed.sourceStart; + return new Region(unblamed.resultStart + blameStartDelta, blamedStart, + length); + } + + // Tests can override this, so they don't need a real repo, commit and walk + protected RevCommit parse(ObjectId oid) throws IOException { + return rw.parseCommit(oid); + } + + private static Candidate asLinkedCandidate(List<Candidate> c) { + Candidate head = c.get(0); + Candidate tail = head; + for (int i = 1; i < c.size(); i++) { + tail.queueNext = c.get(i); + tail = tail.queueNext; + } + return head; + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java index 5e2746c..48f6b7e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java
@@ -79,6 +79,7 @@ public static BlameResult create(BlameGenerator gen) throws IOException { BlameResult(BlameGenerator bg, String path, RawText text) { generator = bg; + generator.setUseCache(false); resultPath = path; resultContents = text;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/BlameCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/BlameCache.java new file mode 100644 index 0000000..d44fb5f --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/BlameCache.java
@@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * 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.blame.cache; + +import java.io.IOException; +import java.util.List; + +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; + +/** + * Keeps the blame information for a path at certain commit. + * <p> + * If there is a result, it covers the whole file at that revision + * + * @since 7.2 + */ +public interface BlameCache { + /** + * Gets the blame of a path at a given commit if available. + * <p> + * Since this cache is used in blame calculation, this get() method should + * only retrieve the cache value, and not re-trigger blame calculation. In + * other words, this acts as "getIfPresent", and not "computeIfAbsent". + * + * @param repo + * repository containing the commit + * @param commitId + * we are looking at the file in this revision + * @param path + * path a file in the repo + * + * @return the blame of a path at a given commit or null if not in cache + * @throws IOException + * error retrieving/parsing values from storage + */ + List<CacheRegion> get(Repository repo, ObjectId commitId, String path) + throws IOException; +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/CacheRegion.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/CacheRegion.java new file mode 100644 index 0000000..cf3f978 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/CacheRegion.java
@@ -0,0 +1,125 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * 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.blame.cache; + +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.ObjectId; + +/** + * Region of the blame of a file. + * <p> + * Usually all parameters are non-null, except when the Region was created + * to fill an unblamed gap (to cover for bugs in the calculation). In that + * case, path, commit and author will be null. + * + * @since 7.2 + **/ +public class CacheRegion implements Comparable<CacheRegion> { + private final String sourcePath; + + private final ObjectId sourceCommit; + + private final int end; + + private final int start; + + /** + * A blamed portion of a file + * + * @param path + * location of the file + * @param commit + * commit that is modifying this region + * @param start + * first line of this region (inclusive) + * @param end + * last line of this region (non-inclusive!) + */ + public CacheRegion(String path, ObjectId commit, + int start, int end) { + allOrNoneNull(path, commit); + this.sourcePath = path; + this.sourceCommit = commit; + this.start = start; + this.end = end; + } + + /** + * First line of this region. Starting by 0, inclusive + * + * @return first line of this region. + */ + public int getStart() { + return start; + } + + /** + * One after last line in this region (or: last line non-inclusive) + * + * @return one after last line in this region. + */ + public int getEnd() { + return end; + } + + + /** + * Path of the file this region belongs to + * + * @return path in the repo/commit + */ + public String getSourcePath() { + return sourcePath; + } + + /** + * Commit this region belongs to + * + * @return commit for this region + */ + public ObjectId getSourceCommit() { + return sourceCommit; + } + + @Override + public int compareTo(CacheRegion o) { + return start - o.start; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (sourceCommit != null) { + sb.append(sourceCommit.name(), 0, 7).append(' ') + .append(" (") + .append(sourcePath).append(')'); + } else { + sb.append("<unblamed region>"); + } + sb.append(' ').append("start=").append(start).append(", count=") + .append(end - start); + return sb.toString(); + } + + private static void allOrNoneNull(String path, ObjectId commit) { + if (path != null && commit != null) { + return; + } + + if (path == null && commit == null) { + return; + } + throw new IllegalArgumentException(MessageFormat + .format(JGitText.get().cacheRegionAllOrNoneNull, path, commit)); + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java new file mode 100644 index 0000000..b744444 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java
@@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License 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.diff; + +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Built-in drivers for various languages, sorted by name. These drivers will be + * used to determine function names for a hunk. + * <p> + * When writing or updating patterns, assume the contents are syntactically + * correct. Patterns can be simple and need not cover all syntactical corner + * cases, as long as they are sufficiently permissive. + * + * @since 6.10.1 + */ +@SuppressWarnings({"ImmutableEnumChecker", "nls"}) +public enum DiffDriver { + /** + * Built-in diff driver for <a href= + * "https://learn.microsoft.com/en-us/cpp/cpp/cpp-language-reference">c++</a> + */ + cpp(List.of( + /* Jump targets or access declarations */ + "^[ \\t]*[A-Za-z_][A-Za-z_0-9]*:\\s*($|/[/*])"), List.of( + /* functions/methods, variables, and compounds at top level */ + "^((::\\s*)?[A-Za-z_].*)$")), + /** + * Built-in diff driver for <a href= + * "https://devicetree-specification.readthedocs.io/en/stable/source-language.html">device + * tree files</a> + */ + dts(List.of(";", "="), List.of( + /* lines beginning with a word optionally preceded by '&' or the root */ + "^[ \\t]*((/[ \\t]*\\{|&?[a-zA-Z_]).*)")), + /** + * Built-in diff driver for <a href= + * "https://docs.oracle.com/javase/specs/jls/se21/html/index.html">java</a> + */ + java(List.of( + "^[ \\t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)"), + List.of( + /* Class, enum, interface, and record declarations */ + "^[ \\t]*(([a-z-]+[ \\t]+)*(class|enum|interface|record)[ \\t]+.*)$", + /* Method definitions; note that constructor signatures are not */ + /* matched because they are indistinguishable from method calls. */ + "^[ \\t]*(([A-Za-z_<>&\\]\\[][?&<>.,A-Za-z_0-9]*[ \\t]+)+[A-Za-z_]" + + "[A-Za-z_0-9]*[ \\t]*\\([^;]*)$")), + /** + * Built-in diff driver for + * <a href="https://docs.python.org/3/reference/index.html">python</a> + */ + python(List.of("^[ \\t]*((class|(async[ \\t]+)?def)[ \\t].*)$")), + /** + * Built-in diff driver for + * <a href="https://doc.rust-lang.org/reference/introduction.html">rust</a> + */ + rust(List.of("^[\\t ]*((pub(\\([^\\)]+\\))?[\\t ]+)?" + + "((async|const|unsafe|extern([\\t ]+\"[^\"]+\"))[\\t ]+)?" + + "(struct|enum|union|mod|trait|fn|impl|macro_rules!)[< \\t]+[^;]*)$")); + + private final List<Pattern> negatePatterns; + + private final List<Pattern> matchPatterns; + + DiffDriver(List<String> negate, List<String> match, int flags) { + if (negate != null) { + this.negatePatterns = negate.stream() + .map(r -> Pattern.compile(r, flags)) + .collect(Collectors.toList()); + } else { + this.negatePatterns = null; + } + this.matchPatterns = match.stream().map(r -> Pattern.compile(r, flags)) + .collect(Collectors.toList()); + } + + DiffDriver(List<String> match) { + this(null, match, 0); + } + + DiffDriver(List<String> negate, List<String> match) { + this(negate, match, 0); + } + + /** + * Returns the list of patterns used to exclude certain lines from being + * considered as function names. + * + * @return the list of negate patterns + */ + public List<Pattern> getNegatePatterns() { + return negatePatterns; + } + + /** + * Returns the list of patterns used to match lines for potential function + * names. + * + * @return the list of match patterns + */ + public List<Pattern> getMatchPatterns() { + return matchPatterns; + } +}
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 2f472b5..cbac3f9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -30,7 +30,9 @@ import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; import org.eclipse.jgit.api.errors.CanceledException; +import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.dircache.DirCacheIterator; @@ -703,7 +705,7 @@ public void format(List<? extends DiffEntry> entries) throws IOException { */ public void format(DiffEntry ent) throws IOException { FormatResult res = createFormatResult(ent); - format(res.header, res.a, res.b); + format(res.header, res.a, res.b, getDiffDriver(ent)); } private static byte[] writeGitLinkText(AbbreviatedObjectId id) { @@ -749,11 +751,14 @@ private String quotePath(String path) { * text source for the post-image version of the content. This * must match the content of * {@link org.eclipse.jgit.patch.FileHeader#getNewId()}. + * @param diffDriver + * the diff driver used to obtain function names in hunk headers * @throws java.io.IOException - * writing to the supplied stream failed. + * writing to the supplied stream failed. + * @since 6.10.1 */ - public void format(FileHeader head, RawText a, RawText b) - throws IOException { + public void format(FileHeader head, RawText a, RawText b, + DiffDriver diffDriver) throws IOException { // Reuse the existing FileHeader as-is by blindly copying its // header lines, but avoiding its hunks. Instead we recreate // the hunks from the text instances we have been supplied. @@ -763,8 +768,49 @@ public void format(FileHeader head, RawText a, RawText b) if (!head.getHunks().isEmpty()) end = head.getHunks().get(0).getStartOffset(); out.write(head.getBuffer(), start, end - start); - if (head.getPatchType() == PatchType.UNIFIED) - format(head.toEditList(), a, b); + if (head.getPatchType() == PatchType.UNIFIED) { + format(head.toEditList(), a, b, diffDriver); + } + } + + /** + * Format a patch script, reusing a previously parsed FileHeader. + * <p> + * This formatter is primarily useful for editing an existing patch script + * to increase or reduce the number of lines of context within the script. + * All header lines are reused as-is from the supplied FileHeader. + * + * @param head + * existing file header containing the header lines to copy. + * @param a + * text source for the pre-image version of the content. This must match + * the content of {@link org.eclipse.jgit.patch.FileHeader#getOldId()}. + * @param b + * text source for the post-image version of the content. This must match + * the content of {@link org.eclipse.jgit.patch.FileHeader#getNewId()}. + * @throws java.io.IOException + * writing to the supplied stream failed. + */ + public void format(FileHeader head, RawText a, RawText b) + throws IOException { + format(head, a, b, null); + } + + /** + * Formats a list of edits in unified diff format + * + * @param edits + * some differences which have been calculated between A and B + * @param a + * the text A which was compared + * @param b + * the text B which was compared + * @throws java.io.IOException + * if an IO error occurred + */ + public void format(EditList edits, RawText a, RawText b) + throws IOException { + format(edits, a, b, null); } /** @@ -776,11 +822,14 @@ public void format(FileHeader head, RawText a, RawText b) * the text A which was compared * @param b * the text B which was compared + * @param diffDriver + * the diff driver used to obtain function names in hunk headers * @throws java.io.IOException * if an IO error occurred + * @since 6.10.1 */ - public void format(EditList edits, RawText a, RawText b) - throws IOException { + public void format(EditList edits, RawText a, RawText b, + DiffDriver diffDriver) throws IOException { for (int curIdx = 0; curIdx < edits.size();) { Edit curEdit = edits.get(curIdx); final int endIdx = findCombinedEnd(edits, curIdx); @@ -791,7 +840,8 @@ public void format(EditList edits, RawText a, RawText b) final int aEnd = (int) Math.min(a.size(), (long) endEdit.getEndA() + context); final int bEnd = (int) Math.min(b.size(), (long) endEdit.getEndB() + context); - writeHunkHeader(aCur, aEnd, bCur, bEnd); + writeHunkHeader(aCur, aEnd, bCur, bEnd, + getFuncName(a, aCur - 1, diffDriver)); while (aCur < aEnd || bCur < bEnd) { if (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) { @@ -881,8 +931,30 @@ protected void writeRemovedLine(RawText text, int line) * @throws java.io.IOException * if an IO error occurred */ - protected void writeHunkHeader(int aStartLine, int aEndLine, - int bStartLine, int bEndLine) throws IOException { + protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, + int bEndLine) throws IOException { + writeHunkHeader(aStartLine, aEndLine, bStartLine, bEndLine, null); + } + + /** + * Output a hunk header + * + * @param aStartLine + * within first source + * @param aEndLine + * within first source + * @param bStartLine + * within second source + * @param bEndLine + * within second source + * @param funcName + * function name of this hunk + * @throws java.io.IOException + * if an IO error occurred + * @since 6.10.1 + */ + protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, + int bEndLine, String funcName) throws IOException { out.write('@'); out.write('@'); writeRange('-', aStartLine + 1, aEndLine - aStartLine); @@ -890,6 +962,10 @@ protected void writeHunkHeader(int aStartLine, int aEndLine, out.write(' '); out.write('@'); out.write('@'); + if (funcName != null) { + out.write(' '); + out.write(funcName.getBytes()); + } out.write('\n'); } @@ -1247,4 +1323,50 @@ private boolean combineB(List<Edit> e, int i) { private static boolean end(Edit edit, int a, int b) { return edit.getEndA() <= a && edit.getEndB() <= b; } + + private String getFuncName(RawText text, int startAt, + DiffDriver diffDriver) { + if (diffDriver != null) { + while (startAt > 0) { + String line = text.getString(startAt); + startAt--; + if (matchesAny(diffDriver.getNegatePatterns(), line)) { + continue; + } + if (matchesAny(diffDriver.getMatchPatterns(), line)) { + String funcName = line.replaceAll("^[ \\t]+", ""); //$NON-NLS-1$//$NON-NLS-2$ + return funcName.substring(0, + Math.min(funcName.length(), 80)).trim(); + } + } + } + return null; + } + + private boolean matchesAny(List<Pattern> patterns, String text) { + if (patterns != null) { + for (Pattern p : patterns) { + if (p.matcher(text).find()) { + return true; + } + } + } + return false; + } + + private DiffDriver getDiffDriver(DiffEntry entry) { + Attribute diffAttr = entry.getDiffAttribute(); + if (diffAttr == null) { + return null; + } + String diffAttrValue = diffAttr.getValue(); + if (diffAttrValue == null) { + return null; + } + try { + return DiffDriver.valueOf(diffAttrValue); + } catch (IllegalArgumentException e) { + return null; + } + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java index 4343642..b401bbe 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java
@@ -44,8 +44,8 @@ public ObjectId getCalulatedPatchId() { } @Override - protected void writeHunkHeader(int aStartLine, int aEndLine, - int bStartLine, int bEndLine) throws IOException { + protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, + int bEndLine, String funcName) throws IOException { // The hunk header is not taken into account for patch id calculation }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java index 76dc87e..fdfe533 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
@@ -360,18 +360,22 @@ public static boolean isBinary(byte[] raw, int length, boolean complete) { length = maxLength; isComplete = false; } - byte last = 'x'; // Just something inconspicuous. - for (int ptr = 0; ptr < length; ptr++) { - byte curr = raw[ptr]; - if (isBinary(curr, last)) { + + int ptr = -1; + byte current; + while (ptr < length - 2) { + current = raw[++ptr]; + if (current == '\0' || (current == '\r' && raw[++ptr] != '\n')) { return true; } - last = curr; } - if (isComplete) { - // Buffer contains everything... - return last == '\r'; // ... so this must be a lone CR + + if (ptr == length - 2) { + // if '\r' be last, then if isComplete then return binary + current = raw[++ptr]; + return current == '\0' || (current == '\r' && isComplete); } + return false; } @@ -467,26 +471,30 @@ public static boolean isCrLfText(byte[] raw, int length) { */ public static boolean isCrLfText(byte[] raw, int length, boolean complete) { boolean has_crlf = false; - byte last = 'x'; // Just something inconspicuous - for (int ptr = 0; ptr < length; ptr++) { - byte curr = raw[ptr]; - if (isBinary(curr, last)) { + + int ptr = -1; + byte current; + while (ptr < length - 2) { + current = raw[++ptr]; + if (current == '\0') { return false; } - if (curr == '\n' && last == '\r') { + if (current == '\r') { + if (raw[++ptr] != '\n') { + return false; + } has_crlf = true; } - last = curr; } - if (last == '\r') { - if (complete) { - // Lone CR: it's binary after all. + + if (ptr == length - 2) { + // if '\r' be last, then if isComplete then return binary + current = raw[++ptr]; + if (current == '\0' || (current == '\r' && complete)) { return false; } - // Tough call. If the next byte, which we don't have, would be a - // '\n', it'd be a CR-LF text, otherwise it'd be binary. Just decide - // based on what we already scanned; it wasn't binary until now. } + return has_crlf; } @@ -578,4 +586,5 @@ public static RawText load(ObjectLoader ldr, int threshold) return new RawText(data, RawParseUtils.lineMapOrBinary(data, 0, (int) sz)); } } + }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java index 5de7bac..fb98df7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java
@@ -80,7 +80,7 @@ class SimilarityRenameDetector { private long[] matrix; /** Score a pair must exceed to be considered a rename. */ - private int renameScore = 60; + private int renameScore = 50; /** * File size threshold (in bytes) for detecting renames. Files larger
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java index accf732..de02aec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java
@@ -217,10 +217,18 @@ public void checkout(DirCacheEntry entry, CheckoutMetadata metadata, } } try { - if (recursiveDelete && Files.isDirectory(f.toPath(), - LinkOption.NOFOLLOW_LINKS)) { + boolean isDir = Files.isDirectory(f.toPath(), + LinkOption.NOFOLLOW_LINKS); + if (recursiveDelete && isDir) { FileUtils.delete(f, FileUtils.RECURSIVE); } + if (cache.getRepository().isWorkTreeCaseInsensitive() && !isDir) { + // We cannot rely on rename via Files.move() to work correctly + // if the target exists in a case variant. For instance with JDK + // 17 on Mac OS, the existing case-variant name is kept. On + // Windows 11 it would work and use the name given in 'f'. + FileUtils.delete(f, FileUtils.SKIP_MISSING); + } FileUtils.rename(tmpFile, f, StandardCopyOption.ATOMIC_MOVE); cachedParent.remove(f.getName()); } catch (IOException e) {
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 34dba0b..c650d6e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -1037,7 +1037,12 @@ private void updateSmudgedEntries() throws IOException { } } - enum DirCacheVersion implements ConfigEnum { + /** + * DirCache versions + * + * @since 7.2 + */ + public enum DirCacheVersion implements ConfigEnum { /** Minimum index version on-disk format that we support. */ DIRC_VERSION_MINIMUM(2), @@ -1060,6 +1065,9 @@ private DirCacheVersion(int versionCode) { this.version = versionCode; } + /** + * @return the version code for this version + */ public int getVersionCode() { return version; } @@ -1078,6 +1086,13 @@ public boolean matchConfigValue(String in) { } } + /** + * Create DirCacheVersion from integer value of the version code. + * + * @param val + * integer value of the version code. + * @return the DirCacheVersion instance of the version code. + */ public static DirCacheVersion fromInt(int val) { for (DirCacheVersion v : DirCacheVersion.values()) { if (val == v.getVersionCode()) { @@ -1098,9 +1113,8 @@ 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, + indexVersion = cfg.getEnum(ConfigConstants.CONFIG_INDEX_SECTION, + null, ConfigConstants.CONFIG_KEY_VERSION, manyFiles ? DirCacheVersion.DIRC_VERSION_PATHCOMPRESS : DirCacheVersion.DIRC_VERSION_EXTENDED); skipHash = cfg.getBoolean(ConfigConstants.CONFIG_INDEX_SECTION,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java index 6ae5153..18d7748 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -5,7 +5,7 @@ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2010, Chrisian Halstrick <christian.halstrick@sap.com> * Copyright (C) 2019, 2020, Andre Bossert <andre.bossert@siemens.com> - * Copyright (C) 2017, 2023, Thomas Wolf <twolf@apache.org> and others + * Copyright (C) 2017, 2025, Thomas Wolf <twolf@apache.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 @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.api.errors.FilterFailedException; @@ -66,7 +67,6 @@ import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS.ExecutionResult; -import org.eclipse.jgit.util.IntList; import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.io.EolStreamTypeUtil; import org.slf4j.Logger; @@ -113,9 +113,11 @@ public CheckoutMetadata(EolStreamType eolStreamType, private Map<String, CheckoutMetadata> updated = new LinkedHashMap<>(); + private Set<String> existing; + private ArrayList<String> conflicts = new ArrayList<>(); - private ArrayList<String> removed = new ArrayList<>(); + private TreeSet<String> removed; private ArrayList<String> kept = new ArrayList<>(); @@ -185,7 +187,7 @@ public List<String> getToBeDeleted() { * @return a list of all files removed by this checkout */ public List<String> getRemoved() { - return removed; + return new ArrayList<>(removed); } /** @@ -214,6 +216,14 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc, this.mergeCommitTree = mergeCommitTree; this.workingTree = workingTree; this.initialCheckout = !repo.isBare() && !repo.getIndexFile().exists(); + boolean caseInsensitive = !repo.isBare() + && repo.isWorkTreeCaseInsensitive(); + this.removed = caseInsensitive + ? new TreeSet<>(String::compareToIgnoreCase) + : new TreeSet<>(); + this.existing = caseInsensitive + ? new TreeSet<>(String::compareToIgnoreCase) + : null; } /** @@ -400,9 +410,11 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, // content to be checked out. update(m); } - } else + } else { update(m); - } else if (f == null || !m.idEqual(i)) { + } + } else if (f == null || !m.idEqual(i) + || m.getEntryRawMode() != i.getEntryRawMode()) { // The working tree file is missing or the merge content differs // from index content update(m); @@ -410,11 +422,11 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, // The index contains a file (and not a folder) if (f.isModified(i.getDirCacheEntry(), true, this.walk.getObjectReader()) - || i.getDirCacheEntry().getStage() != 0) + || i.getDirCacheEntry().getStage() != 0) { // The working tree file is dirty or the index contains a // conflict update(m); - else { + } else { // update the timestamp of the index with the one from the // file if not set, as we are sure to be in sync here. DirCacheEntry entry = i.getDirCacheEntry(); @@ -424,9 +436,10 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, } keep(i.getEntryPathString(), entry, f); } - } else + } else { // The index contains a folder keep(i.getEntryPathString(), i.getDirCacheEntry(), f); + } } else { // There is no entry in the merge commit. Means: we want to delete // what's currently in the index and working tree @@ -521,6 +534,13 @@ private boolean doCheckout() throws CorruptObjectException, IOException, // update our index builder.finish(); + // On case-insensitive file systems we may have a case variant kept + // and another one removed. In that case, don't remove it. + if (existing != null) { + removed.removeAll(existing); + existing.clear(); + } + // init progress reporting int numTotal = removed.size() + updated.size() + conflicts.size(); monitor.beginTask(JGitText.get().checkingOutFiles, numTotal); @@ -531,9 +551,9 @@ private boolean doCheckout() throws CorruptObjectException, IOException, // when deleting files process them in the opposite order as they have // been reported. This ensures the files are deleted before we delete // their parent folders - IntList nonDeleted = new IntList(); - for (int i = removed.size() - 1; i >= 0; i--) { - String r = removed.get(i); + Iterator<String> iter = removed.descendingIterator(); + while (iter.hasNext()) { + String r = iter.next(); file = new File(repo.getWorkTree(), r); if (!file.delete() && repo.getFS().exists(file)) { // The list of stuff to delete comes from the index @@ -542,7 +562,7 @@ private boolean doCheckout() throws CorruptObjectException, IOException, // to delete it. A submodule is not empty, so it // is safe to check this after a failed delete. if (!repo.getFS().isDirectory(file)) { - nonDeleted.add(i); + iter.remove(); toBeDeleted.add(r); } } else { @@ -560,8 +580,6 @@ private boolean doCheckout() throws CorruptObjectException, IOException, if (file != null) { removeEmptyParents(file); } - removed = filterOut(removed, nonDeleted); - nonDeleted = null; Iterator<Map.Entry<String, CheckoutMetadata>> toUpdate = updated .entrySet().iterator(); Map.Entry<String, CheckoutMetadata> e = null; @@ -633,36 +651,6 @@ private boolean doCheckout() throws CorruptObjectException, IOException, return toBeDeleted.isEmpty(); } - private static ArrayList<String> filterOut(ArrayList<String> strings, - IntList indicesToRemove) { - int n = indicesToRemove.size(); - if (n == strings.size()) { - return new ArrayList<>(0); - } - switch (n) { - case 0: - return strings; - case 1: - strings.remove(indicesToRemove.get(0)); - return strings; - default: - int length = strings.size(); - ArrayList<String> result = new ArrayList<>(length - n); - // Process indicesToRemove from the back; we know that it - // contains indices in descending order. - int j = n - 1; - int idx = indicesToRemove.get(j); - for (int i = 0; i < length; i++) { - if (i == idx) { - idx = (--j >= 0) ? indicesToRemove.get(j) : -1; - } else { - result.add(strings.get(i)); - } - } - return result; - } - } - private static boolean isSamePrefix(String a, String b) { int as = a.lastIndexOf('/'); int bs = b.lastIndexOf('/'); @@ -1233,6 +1221,9 @@ private void keep(String path, DirCacheEntry e, WorkingTreeIterator f) if (!FileMode.TREE.equals(e.getFileMode())) { builder.add(e); } + if (existing != null) { + existing.add(path); + } if (force) { if (f == null || f.isModified(e, true, walk.getObjectReader())) { kept.add(path); @@ -1401,127 +1392,6 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree) } /** - * Updates the file in the working tree with content and mode from an entry - * in the index. The new content is first written to a new temporary file in - * the same directory as the real file. Then that new file is renamed to the - * final filename. - * - * <p> - * <b>Note:</b> if the entry path on local file system exists as a non-empty - * directory, and the target entry type is a link or file, the checkout will - * fail with {@link java.io.IOException} since existing non-empty directory - * cannot be renamed to file or link without deleting it recursively. - * </p> - * - * @param repo - * repository managing the destination work tree. - * @param entry - * the entry containing new mode and content - * @param or - * object reader to use for checkout - * @throws java.io.IOException - * if an IO error occurred - * @since 3.6 - * @deprecated since 5.1, use - * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata, WorkingTreeOptions)} - * instead - */ - @Deprecated - public static void checkoutEntry(Repository repo, DirCacheEntry entry, - ObjectReader or) throws IOException { - checkoutEntry(repo, entry, or, false, null, null); - } - - - /** - * Updates the file in the working tree with content and mode from an entry - * in the index. The new content is first written to a new temporary file in - * the same directory as the real file. Then that new file is renamed to the - * final filename. - * - * <p> - * <b>Note:</b> if the entry path on local file system exists as a file, it - * will be deleted and if it exists as a directory, it will be deleted - * recursively, independently if has any content. - * </p> - * - * @param repo - * repository managing the destination work tree. - * @param entry - * the entry containing new mode and content - * @param or - * object reader to use for checkout - * @param deleteRecursive - * true to recursively delete final path if it exists on the file - * system - * @param checkoutMetadata - * containing - * <ul> - * <li>smudgeFilterCommand to be run for smudging the entry to be - * checked out</li> - * <li>eolStreamType used for stream conversion</li> - * </ul> - * @throws java.io.IOException - * if an IO error occurred - * @since 4.2 - * @deprecated since 6.3, use - * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata, WorkingTreeOptions)} - * instead - */ - @Deprecated - public static void checkoutEntry(Repository repo, DirCacheEntry entry, - ObjectReader or, boolean deleteRecursive, - CheckoutMetadata checkoutMetadata) throws IOException { - checkoutEntry(repo, entry, or, deleteRecursive, checkoutMetadata, null); - } - - /** - * Updates the file in the working tree with content and mode from an entry - * in the index. The new content is first written to a new temporary file in - * the same directory as the real file. Then that new file is renamed to the - * final filename. - * - * <p> - * <b>Note:</b> if the entry path on local file system exists as a file, it - * will be deleted and if it exists as a directory, it will be deleted - * recursively, independently if has any content. - * </p> - * - * @param repo - * repository managing the destination work tree. - * @param entry - * the entry containing new mode and content - * @param or - * object reader to use for checkout - * @param deleteRecursive - * true to recursively delete final path if it exists on the file - * system - * @param checkoutMetadata - * containing - * <ul> - * <li>smudgeFilterCommand to be run for smudging the entry to be - * checked out</li> - * <li>eolStreamType used for stream conversion</li> - * </ul> - * @param options - * {@link WorkingTreeOptions} that are effective; if {@code null} - * they are loaded from the repository config - * @throws java.io.IOException - * if an IO error occurred - * @since 6.3 - * @deprecated since 6.6.1; use {@link Checkout} instead - */ - @Deprecated - public static void checkoutEntry(Repository repo, DirCacheEntry entry, - ObjectReader or, boolean deleteRecursive, - CheckoutMetadata checkoutMetadata, WorkingTreeOptions options) - throws IOException { - Checkout checkout = new Checkout(repo, options) - .setRecursiveDeletion(deleteRecursive); - checkout.checkout(entry, checkoutMetadata, or, null); - } - - /** * Return filtered content for a specific object (blob). EOL handling and * smudge-filter handling are applied in the same way as it would be done * during a checkout. @@ -1647,6 +1517,8 @@ private static void runExternalFilterCommand(Repository repo, String path, filterProcessBuilder.directory(repo.getWorkTree()); filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY, repo.getDirectory().getAbsolutePath()); + filterProcessBuilder.environment().put(Constants.GIT_COMMON_DIR_KEY, + repo.getCommonDirectory().getAbsolutePath()); ExecutionResult result; int rc; try {
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 c5e1e4e..5a22938 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -396,28 +396,6 @@ void write(OutputStream os, DirCacheVersion version, DirCacheEntry previous) * timestamp. This method tests to see if file was written out at the same * time as the index. * - * @param smudge_s - * seconds component of the index's last modified time. - * @param smudge_ns - * nanoseconds component of the index's last modified time. - * @return true if extra careful checks should be used. - * @deprecated use {@link #mightBeRacilyClean(Instant)} instead - */ - @Deprecated - public final boolean mightBeRacilyClean(int smudge_s, int smudge_ns) { - return mightBeRacilyClean(Instant.ofEpochSecond(smudge_s, smudge_ns)); - } - - /** - * Is it possible for this entry to be accidentally assumed clean? - * <p> - * The "racy git" problem happens when a work file can be updated faster - * than the filesystem records file modification timestamps. It is possible - * for an application to edit a work file, update the index, then edit it - * again before the filesystem will give the work file a new modification - * timestamp. This method tests to see if file was written out at the same - * time as the index. - * * @param smudge * index's last modified time. * @return true if extra careful checks should be used. @@ -653,22 +631,6 @@ public void setCreationTime(long when) { } /** - * Get the cached last modification date of this file, in milliseconds. - * <p> - * One of the indicators that the file has been modified by an application - * changing the working tree is if the last modification time for the file - * differs from the time stored in this entry. - * - * @return last modification time of this file, in milliseconds since the - * Java epoch (midnight Jan 1, 1970 UTC). - * @deprecated use {@link #getLastModifiedInstant()} instead - */ - @Deprecated - public long getLastModified() { - return decodeTS(P_MTIME); - } - - /** * Get the cached last modification date of this file. * <p> * One of the indicators that the file has been modified by an application @@ -683,18 +645,6 @@ public Instant getLastModifiedInstant() { } /** - * Set the cached last modification date of this file, using milliseconds. - * - * @param when - * new cached modification date of the file, in milliseconds. - * @deprecated use {@link #setLastModified(Instant)} instead - */ - @Deprecated - public void setLastModified(long when) { - encodeTS(P_MTIME, when); - } - - /** * Set the cached last modification date of this file. * * @param when
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java index 1fd8086..38982fd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/PackInvalidException.java
@@ -23,18 +23,6 @@ public class PackInvalidException extends IOException { private static final long serialVersionUID = 1L; /** - * Construct a pack invalid error. - * - * @param path - * path of the invalid pack file. - * @deprecated Use {@link #PackInvalidException(File, Throwable)}. - */ - @Deprecated - public PackInvalidException(File path) { - this(path, null); - } - - /** * Construct a pack invalid error with cause. * * @param path @@ -48,18 +36,6 @@ public PackInvalidException(File path, Throwable cause) { } /** - * Construct a pack invalid error. - * - * @param path - * path of the invalid pack file. - * @deprecated Use {@link #PackInvalidException(String, Throwable)}. - */ - @Deprecated - public PackInvalidException(String path) { - this(path, null); - } - - /** * Construct a pack invalid error with cause. * * @param path
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java index 3ce97a4..e511a68 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java
@@ -156,6 +156,9 @@ private void prepareIndex(List<RepoProject> projects, DirCache index, ObjectId objectId; if (ObjectId.isId(proj.getRevision())) { objectId = ObjectId.fromString(proj.getRevision()); + if (config.recordRemoteBranch && proj.getUpstream() != null) { + cfg.setString("submodule", name, "ref", proj.getUpstream()); //$NON-NLS-1$//$NON-NLS-2$ + } } else { objectId = callback.sha1(url, proj.getRevision()); if (objectId == null && !config.ignoreRemoteFailures) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java index 957b386..b033177 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -176,6 +176,10 @@ public void startElement( attributes.getValue("groups")); currentProject .setRecommendShallow(attributes.getValue("clone-depth")); + currentProject + .setUpstream(attributes.getValue("upstream")); + currentProject + .setDestBranch(attributes.getValue("dest-branch")); break; case "remote": String alias = attributes.getValue("alias");
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index 95c1c8b..be77fca 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -111,32 +111,6 @@ public interface RemoteReader { public ObjectId sha1(String uri, String ref) throws GitAPIException; /** - * Read a file from a remote repository. - * - * @param uri - * The URI of the remote repository - * @param ref - * The ref (branch/tag/etc.) to read - * @param path - * The relative path (inside the repo) to the file to read - * @return the file content. - * @throws GitAPIException - * If the ref have an invalid or ambiguous name, or it does - * not exist in the repository, - * @throws IOException - * If the object does not exist or is too large - * @since 3.5 - * - * @deprecated Use {@link #readFileWithMode(String, String, String)} - * instead - */ - @Deprecated - public default byte[] readFile(String uri, String ref, String path) - throws GitAPIException, IOException { - return readFileWithMode(uri, ref, path).getContents(); - } - - /** * Read contents and mode (i.e. permissions) of the file from a remote * repository. * @@ -255,7 +229,8 @@ public RemoteFile readFileWithMode(String uri, String ref, String path) @SuppressWarnings("serial") static class ManifestErrorException extends GitAPIException { ManifestErrorException(Throwable cause) { - super(RepoText.get().invalidManifest, cause); + super(RepoText.get().invalidManifest + " " + cause.getMessage(), //$NON-NLS-1$ + cause); } } @@ -615,6 +590,7 @@ private List<RepoProject> renameProjects(List<RepoProject> projects) { p.setUrl(proj.getUrl()); p.addCopyFiles(proj.getCopyFiles()); p.addLinkFiles(proj.getLinkFiles()); + p.setUpstream(proj.getUpstream()); ret.add(p); } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java index 8deb738..2630da3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -38,6 +38,8 @@ public class RepoProject implements Comparable<RepoProject> { private final Set<String> groups; private final List<CopyFile> copyfiles; private final List<LinkFile> linkfiles; + private String upstream; + private String destBranch; private String recommendShallow; private String url; private String defaultRevision; @@ -389,6 +391,57 @@ public void clearLinkFiles() { this.linkfiles.clear(); } + /** + * Return the upstream attribute of the project + * + * @return the upstream value if present, null otherwise. + * + * @since 6.10 + */ + public String getUpstream() { + return this.upstream; + } + + /** + * Return the dest-branch attribute of the project + * + * @return the dest-branch value if present, null otherwise. + * + * @since 6.10 + */ + public String getDestBranch() { + return this.destBranch; + } + + /** + * Set the upstream attribute of the project + * + * Name of the git ref in which a sha1 can be found, when the revision is a + * sha1. + * + * @param upstream + * value of the attribute in the manifest + * + * @since 6.10 + */ + public void setUpstream(String upstream) { + this.upstream = upstream; + } + + /** + * Set the dest-branch attribute of the project + * + * Name of a Git branch. + * + * @param destBranch + * value of the attribute in the manifest + * + * @since 6.10 + */ + public void setDestBranch(String destBranch) { + this.destBranch = destBranch; + } + private String getPathWithSlash() { if (path.endsWith("/")) { //$NON-NLS-1$ return path;
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 700b54a..bf252f9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -94,8 +94,6 @@ public static JGitText get() { /***/ public String binaryHunkInvalidLength; /***/ public String binaryHunkLineTooShort; /***/ public String binaryHunkMissingNewline; - /***/ public String bitmapAccessErrorForPackfile; - /***/ public String bitmapFailedToGet; /***/ public String bitmapMissingObject; /***/ public String bitmapsMustBePrepared; /***/ public String bitmapUseNoopNoListener; @@ -108,6 +106,7 @@ public static JGitText get() { /***/ public String buildingBitmaps; /***/ public String cachedPacksPreventsIndexCreation; /***/ public String cachedPacksPreventsListingObjects; + /***/ public String cacheRegionAllOrNoneNull; /***/ public String cannotAccessLastModifiedForSafeDeletion; /***/ public String cannotBeCombined; /***/ public String cannotBeRecursiveWhenTreesAreIncluded; @@ -295,6 +294,7 @@ public static JGitText get() { /***/ public String deleteTagUnexpectedResult; /***/ public String deletingBranches; /***/ public String deletingNotSupported; + /***/ public String deprecatedTrustFolderStat; /***/ public String depthMustBeAt1; /***/ public String depthWithUnshallow; /***/ public String destinationIsNotAWildcard; @@ -315,6 +315,9 @@ public static JGitText get() { /***/ public String downloadCancelled; /***/ public String downloadCancelledDuringIndexing; /***/ public String duplicateAdvertisementsOf; + /***/ public String duplicateCacheTablesGiven; + /***/ public String duplicatePackExtensionsForCacheTables; + /***/ public String duplicatePackExtensionsSet; /***/ public String duplicateRef; /***/ public String duplicateRefAttribute; /***/ public String duplicateRemoteRefUpdateIsIllegal; @@ -490,6 +493,7 @@ public static JGitText get() { /***/ public String invalidTimeUnitValue2; /***/ public String invalidTimeUnitValue3; /***/ public String invalidTreeZeroLengthName; + /***/ public String invalidTrustStat; /***/ public String invalidURL; /***/ public String invalidWildcards; /***/ public String invalidRefSpec; @@ -554,6 +558,8 @@ public static JGitText get() { /***/ public String month; /***/ public String months; /***/ public String monthsAgo; + /***/ public String multiPackIndexUnexpectedSize; + /***/ public String multiPackIndexWritingCancelled; /***/ public String multipleMergeBasesFor; /***/ public String nameMustNotBeNullOrEmpty; /***/ public String need2Arguments; @@ -569,6 +575,8 @@ public static JGitText get() { /***/ public String noMergeHeadSpecified; /***/ public String nonBareLinkFilesNotSupported; /***/ public String nonCommitToHeads; + /***/ public String noPackExtConfigurationGiven; + /***/ public String noPackExtGivenForConfiguration; /***/ public String noPathAttributesFound; /***/ public String noSuchRef; /***/ public String noSuchRefKnown; @@ -601,7 +609,6 @@ public static JGitText get() { /***/ public String oldIdMustNotBeNull; /***/ public String onlyOneFetchSupported; /***/ public String onlyOneOperationCallPerConnectionIsSupported; - /***/ public String onlyOpenPgpSupportedForSigning; /***/ public String openFilesMustBeAtLeast1; /***/ public String openingConnection; /***/ public String operationCanceled; @@ -623,6 +630,8 @@ public static JGitText get() { /***/ public String packingCancelledDuringObjectsWriting; /***/ public String packObjectCountMismatch; /***/ public String packRefs; + /***/ public String packRefsFailed; + /***/ public String packRefsSuccessful; /***/ public String packSizeNotSetYet; /***/ public String packTooLargeForIndexVersion1; /***/ public String packWasDeleted; @@ -639,6 +648,7 @@ public static JGitText get() { /***/ public String personIdentEmailNonNull; /***/ public String personIdentNameNonNull; /***/ public String postCommitHookFailed; + /***/ public String precedenceTrustConfig; /***/ public String prefixRemote; /***/ public String problemWithResolvingPushRefSpecsLocally; /***/ public String progressMonUploading; @@ -666,8 +676,6 @@ public static JGitText get() { /***/ public String readerIsRequired; /***/ public String readingObjectsFromLocalRepositoryFailed; /***/ public String readLastModifiedFailed; - /***/ public String readPipeIsNotAllowed; - /***/ public String readPipeIsNotAllowedRequiredPermission; /***/ public String readTimedOut; /***/ public String receivePackObjectTooLarge1; /***/ public String receivePackObjectTooLarge2; @@ -747,6 +755,8 @@ public static JGitText get() { /***/ public String shutdownCleanup; /***/ public String shutdownCleanupFailed; /***/ public String shutdownCleanupListenerFailed; + /***/ public String signatureServiceConflict; + /***/ public String signatureTypeUnknown; /***/ public String signatureVerificationError; /***/ public String signatureVerificationUnavailable; /***/ public String signedTagMessageNoLf; @@ -833,6 +843,7 @@ public static JGitText get() { /***/ public String unableToCheckConnectivity; /***/ public String unableToCreateNewObject; /***/ public String unableToReadFullInt; + /***/ public String unableToReadFullArray; /***/ public String unableToReadPackfile; /***/ public String unableToRemovePath; /***/ public String unableToWrite; @@ -858,6 +869,7 @@ public static JGitText get() { /***/ public String unknownObjectInIndex; /***/ public String unknownObjectType; /***/ public String unknownObjectType2; + /***/ public String unknownPackExtension; /***/ public String unknownPositionEncoding; /***/ public String unknownRefStorageFormat; /***/ public String unknownRepositoryFormat;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriter.java index 0d9815e..55539e2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/commitgraph/CommitGraphWriter.java
@@ -52,6 +52,7 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.NB; /** @@ -71,6 +72,9 @@ public class CommitGraphWriter { private static final int MAX_CHANGED_PATHS = 512; + private static final PathDiffCalculator PATH_DIFF_CALCULATOR + = new PathDiffCalculator(); + private final int hashsz; private final GraphCommits graphCommits; @@ -374,37 +378,6 @@ private void writeCommitData(CancellableDigestOutputStream out) return generations; } - private static Optional<HashSet<ByteBuffer>> computeBloomFilterPaths( - ObjectReader or, RevCommit cmit) throws MissingObjectException, - IncorrectObjectTypeException, CorruptObjectException, IOException { - HashSet<ByteBuffer> paths = new HashSet<>(); - try (TreeWalk walk = new TreeWalk(null, or)) { - walk.setRecursive(true); - if (cmit.getParentCount() == 0) { - walk.addTree(new EmptyTreeIterator()); - } else { - walk.addTree(cmit.getParent(0).getTree()); - } - walk.addTree(cmit.getTree()); - while (walk.next()) { - if (walk.idEqual(0, 1)) { - continue; - } - byte[] rawPath = walk.getRawPath(); - paths.add(ByteBuffer.wrap(rawPath)); - for (int i = 0; i < rawPath.length; i++) { - if (rawPath[i] == '/') { - paths.add(ByteBuffer.wrap(rawPath, 0, i)); - } - if (paths.size() > MAX_CHANGED_PATHS) { - return Optional.empty(); - } - } - } - } - return Optional.of(paths); - } - private BloomFilterChunks computeBloomFilterChunks(ProgressMonitor monitor) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException { @@ -435,8 +408,8 @@ private BloomFilterChunks computeBloomFilterChunks(ProgressMonitor monitor) filtersReused++; } else { filtersComputed++; - Optional<HashSet<ByteBuffer>> paths = computeBloomFilterPaths( - graphCommits.getObjectReader(), cmit); + Optional<HashSet<ByteBuffer>> paths = PATH_DIFF_CALCULATOR + .changedPaths(graphCommits.getObjectReader(), cmit); if (paths.isEmpty()) { cpf = ChangedPathFilter.FULL; } else { @@ -473,6 +446,44 @@ private void writeExtraEdges(CancellableDigestOutputStream out) } } + // Visible for testing + static class PathDiffCalculator { + + // Walk steps in the last invocation of changedPaths + int stepCounter; + + Optional<HashSet<ByteBuffer>> changedPaths( + ObjectReader or, RevCommit cmit) throws MissingObjectException, + IncorrectObjectTypeException, CorruptObjectException, IOException { + stepCounter = 0; + HashSet<ByteBuffer> paths = new HashSet<>(); + try (TreeWalk walk = new TreeWalk(null, or)) { + walk.setRecursive(true); + walk.setFilter(TreeFilter.ANY_DIFF); + if (cmit.getParentCount() == 0) { + walk.addTree(new EmptyTreeIterator()); + } else { + walk.addTree(cmit.getParent(0).getTree()); + } + walk.addTree(cmit.getTree()); + while (walk.next()) { + stepCounter += 1; + byte[] rawPath = walk.getRawPath(); + paths.add(ByteBuffer.wrap(rawPath)); + for (int i = 0; i < rawPath.length; i++) { + if (rawPath[i] == '/') { + paths.add(ByteBuffer.wrap(rawPath, 0, i)); + } + if (paths.size() > MAX_CHANGED_PATHS) { + return Optional.empty(); + } + } + } + } + return Optional.of(paths); + } + } + private static class ChunkHeader { final int id;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java new file mode 100644 index 0000000..295b702 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java
@@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024, 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.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; + +import java.util.List; + +import org.eclipse.jgit.internal.storage.pack.PackExt; + +/** + * Aggregates values for all given {@link BlockCacheStats}. + */ +class AggregatedBlockCacheStats implements BlockCacheStats { + private final List<BlockCacheStats> blockCacheStats; + + static BlockCacheStats fromStatsList( + List<BlockCacheStats> blockCacheStats) { + if (blockCacheStats.size() == 1) { + return blockCacheStats.get(0); + } + return new AggregatedBlockCacheStats(blockCacheStats); + } + + private AggregatedBlockCacheStats(List<BlockCacheStats> blockCacheStats) { + this.blockCacheStats = blockCacheStats; + } + + @Override + public String getName() { + return AggregatedBlockCacheStats.class.getName(); + } + + @Override + public long[] getCurrentSize() { + long[] sums = emptyPackStats(); + for (BlockCacheStats blockCacheStatsEntry : blockCacheStats) { + sums = add(sums, blockCacheStatsEntry.getCurrentSize()); + } + return sums; + } + + @Override + public long[] getHitCount() { + long[] sums = emptyPackStats(); + for (BlockCacheStats blockCacheStatsEntry : blockCacheStats) { + sums = add(sums, blockCacheStatsEntry.getHitCount()); + } + return sums; + } + + @Override + public long[] getMissCount() { + long[] sums = emptyPackStats(); + for (BlockCacheStats blockCacheStatsEntry : blockCacheStats) { + sums = add(sums, blockCacheStatsEntry.getMissCount()); + } + return sums; + } + + @Override + public long[] getTotalRequestCount() { + long[] sums = emptyPackStats(); + for (BlockCacheStats blockCacheStatsEntry : blockCacheStats) { + sums = add(sums, blockCacheStatsEntry.getTotalRequestCount()); + } + return sums; + } + + @Override + public long[] getHitRatio() { + long[] hit = getHitCount(); + long[] miss = getMissCount(); + long[] ratio = new long[Math.max(hit.length, miss.length)]; + for (int i = 0; i < ratio.length; i++) { + if (i >= hit.length) { + ratio[i] = 0; + } else if (i >= miss.length) { + ratio[i] = 100; + } else { + long total = hit[i] + miss[i]; + ratio[i] = total == 0 ? 0 : hit[i] * 100 / total; + } + } + return ratio; + } + + @Override + public long[] getEvictions() { + long[] sums = emptyPackStats(); + for (BlockCacheStats blockCacheStatsEntry : blockCacheStats) { + sums = add(sums, blockCacheStatsEntry.getEvictions()); + } + return sums; + } + + private static long[] emptyPackStats() { + return new long[PackExt.values().length]; + } + + private static long[] add(long[] first, long[] second) { + long[] sums = new long[Integer.max(first.length, second.length)]; + int i; + for (i = 0; i < Integer.min(first.length, second.length); i++) { + sums[i] = first[i] + second[i]; + } + for (int j = i; j < first.length; j++) { + sums[j] = first[i]; + } + for (int j = i; j < second.length; j++) { + sums[j] = second[i]; + } + return sums; + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java index d0907bc..587d482 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java
@@ -12,6 +12,7 @@ import java.io.IOException; import java.time.Duration; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReferenceArray; @@ -47,6 +48,11 @@ * invocations is also fixed in size. */ final class ClockBlockCacheTable implements DfsBlockCacheTable { + /** + * Table name. + */ + private final String name; + /** Number of entries in {@link #table}. */ private final int tableSize; @@ -129,14 +135,20 @@ final class ClockBlockCacheTable implements DfsBlockCacheTable { -1, 0, null); clockHand.next = clockHand; - this.dfsBlockCacheStats = new DfsBlockCacheStats(); + this.name = cfg.getName(); + this.dfsBlockCacheStats = new DfsBlockCacheStats(this.name); this.refLockWaitTime = cfg.getRefLockWaitTimeConsumer(); this.indexEventConsumer = cfg.getIndexEventConsumer(); } @Override - public DfsBlockCacheStats getDfsBlockCacheStats() { - return dfsBlockCacheStats; + public List<BlockCacheStats> getBlockCacheStats() { + return List.of(dfsBlockCacheStats); + } + + @Override + public String getName() { + return name; } @Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java index 56719cf..f8e0831 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java
@@ -11,7 +11,10 @@ package org.eclipse.jgit.internal.storage.dfs; +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; + import java.io.IOException; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.LongStream; @@ -97,7 +100,12 @@ private DfsBlockCache(DfsBlockCacheConfig cfg) { double streamRatio = cfg.getStreamRatio(); maxStreamThroughCache = (long) (maxBytes * streamRatio); - dfsBlockCacheTable = new ClockBlockCacheTable(cfg); + if (!cfg.getPackExtCacheConfigurations().isEmpty()) { + dfsBlockCacheTable = PackExtBlockCacheTable + .fromBlockCacheConfigs(cfg); + } else { + dfsBlockCacheTable = new ClockBlockCacheTable(cfg); + } for (int i = 0; i < PackExt.values().length; ++i) { Integer limit = cfg.getCacheHotMap().get(PackExt.values()[i]); @@ -119,7 +127,7 @@ boolean shouldCopyThroughCache(long length) { * @return total number of bytes in the cache, per pack file extension. */ public long[] getCurrentSize() { - return dfsBlockCacheTable.getDfsBlockCacheStats().getCurrentSize(); + return getAggregatedBlockCacheStats().getCurrentSize(); } /** @@ -138,7 +146,7 @@ public long getFillPercentage() { * extension. */ public long[] getHitCount() { - return dfsBlockCacheTable.getDfsBlockCacheStats().getHitCount(); + return getAggregatedBlockCacheStats().getHitCount(); } /** @@ -149,7 +157,7 @@ public long getFillPercentage() { * extension. */ public long[] getMissCount() { - return dfsBlockCacheTable.getDfsBlockCacheStats().getMissCount(); + return getAggregatedBlockCacheStats().getMissCount(); } /** @@ -158,8 +166,7 @@ public long getFillPercentage() { * @return total number of requests (hit + miss), per pack file extension. */ public long[] getTotalRequestCount() { - return dfsBlockCacheTable.getDfsBlockCacheStats() - .getTotalRequestCount(); + return getAggregatedBlockCacheStats().getTotalRequestCount(); } /** @@ -168,7 +175,7 @@ public long getFillPercentage() { * @return hit ratios */ public long[] getHitRatio() { - return dfsBlockCacheTable.getDfsBlockCacheStats().getHitRatio(); + return getAggregatedBlockCacheStats().getHitRatio(); } /** @@ -179,7 +186,18 @@ public long getFillPercentage() { * file extension. */ public long[] getEvictions() { - return dfsBlockCacheTable.getDfsBlockCacheStats().getEvictions(); + return getAggregatedBlockCacheStats().getEvictions(); + } + + /** + * Get the list of {@link BlockCacheStats} for all underlying caches. + * <p> + * Useful in monitoring caches with breakdown. + * + * @return the list of {@link BlockCacheStats} for all underlying caches. + */ + public List<BlockCacheStats> getAllBlockCacheStats() { + return dfsBlockCacheTable.getBlockCacheStats(); } /** @@ -259,6 +277,11 @@ <T> T get(DfsStreamKey key, long position) { return dfsBlockCacheTable.get(key, position); } + private BlockCacheStats getAggregatedBlockCacheStats() { + return AggregatedBlockCacheStats + .fromStatsList(dfsBlockCacheTable.getBlockCacheStats()); + } + static final class Ref<T> { final DfsStreamKey key;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java index 77273ce..17bf518 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java
@@ -11,17 +11,27 @@ package org.eclipse.jgit.internal.storage.dfs; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_CACHE_PREFIX; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_LIMIT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONCURRENCY_LEVEL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PACK_EXTENSIONS; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO; +import java.io.PrintWriter; import java.text.MessageFormat; import java.time.Duration; +import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.PackExt; @@ -41,25 +51,103 @@ public class DfsBlockCacheConfig { /** Default number of max cache hits. */ public static final int DEFAULT_CACHE_HOT_MAX = 1; + static final String DEFAULT_NAME = "<default>"; //$NON-NLS-1$ + + private String name; + private long blockLimit; + private int blockSize; + private double streamRatio; + private int concurrencyLevel; private Consumer<Long> refLock; + private Map<PackExt, Integer> cacheHotMap; private IndexEventConsumer indexEventConsumer; + private List<DfsBlockCachePackExtConfig> packExtCacheConfigurations; + /** * Create a default configuration. */ public DfsBlockCacheConfig() { + name = DEFAULT_NAME; setBlockLimit(32 * MB); setBlockSize(64 * KB); setStreamRatio(0.30); setConcurrencyLevel(32); cacheHotMap = Collections.emptyMap(); + packExtCacheConfigurations = Collections.emptyList(); + } + + /** + * Print the current cache configuration to the given {@link PrintWriter}. + * + * @param writer + * {@link PrintWriter} to write the cache's configuration to. + */ + public void print(PrintWriter writer) { + print(/* linePrefix= */ "", /* pad= */ " ", writer); //$NON-NLS-1$//$NON-NLS-2$ + } + + /** + * Print the current cache configuration to the given {@link PrintWriter}. + * + * @param linePrefix + * prefix to prepend all writen lines with. Ex a string of 0 or + * more " " entries. + * @param pad + * filler used to extend linePrefix. Ex a multiple of " ". + * @param writer + * {@link PrintWriter} to write the cache's configuration to. + */ + @SuppressWarnings("nls") + private void print(String linePrefix, String pad, PrintWriter writer) { + String currentPrefixLevel = linePrefix; + if (!name.isEmpty() || !packExtCacheConfigurations.isEmpty()) { + writer.println(linePrefix + "Name: " + + (name.isEmpty() ? DEFAULT_NAME : this.name)); + currentPrefixLevel += pad; + } + writer.println(currentPrefixLevel + "BlockLimit: " + blockLimit); + writer.println(currentPrefixLevel + "BlockSize: " + blockSize); + writer.println(currentPrefixLevel + "StreamRatio: " + streamRatio); + writer.println( + currentPrefixLevel + "ConcurrencyLevel: " + concurrencyLevel); + for (Map.Entry<PackExt, Integer> entry : cacheHotMap.entrySet()) { + writer.println(currentPrefixLevel + "CacheHotMapEntry: " + + entry.getKey() + " : " + entry.getValue()); + } + for (DfsBlockCachePackExtConfig extConfig : packExtCacheConfigurations) { + extConfig.print(currentPrefixLevel, pad, writer); + } + } + + /** + * Get the name for the block cache configured by this cache config. + * + * @return the name for the block cache configured by this cache config. + */ + public String getName() { + return name; + } + + /** + * Set the name for the block cache configured by this cache config. + * <p> + * Made visible for testing. + * + * @param name + * the name for the block cache configured by this cache config. + * @return {@code this} + */ + DfsBlockCacheConfig setName(String name) { + this.name = name; + return this; } /** @@ -77,10 +165,10 @@ public long getBlockLimit() { * Set maximum number bytes of heap memory to dedicate to caching pack file * data. * <p> - * It is strongly recommended to set the block limit to be an integer multiple - * of the block size. This constraint is not enforced by this method (since - * it may be called before {@link #setBlockSize(int)}), but it is enforced by - * {@link #fromConfig(Config)}. + * It is strongly recommended to set the block limit to be an integer + * multiple of the block size. This constraint is not enforced by this + * method (since it may be called before {@link #setBlockSize(int)}), but it + * is enforced by {@link #fromConfig(Config)}. * * @param newLimit * maximum number bytes of heap memory to dedicate to caching @@ -89,9 +177,9 @@ public long getBlockLimit() { */ public DfsBlockCacheConfig setBlockLimit(long newLimit) { if (newLimit <= 0) { - throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().blockLimitNotPositive, - Long.valueOf(newLimit))); + throw new IllegalArgumentException( + MessageFormat.format(JGitText.get().blockLimitNotPositive, + Long.valueOf(newLimit))); } blockLimit = newLimit; return this; @@ -211,12 +299,24 @@ public Map<PackExt, Integer> getCacheHotMap() { * map of hot count per pack extension for {@code DfsBlockCache}. * @return {@code this} */ + /* + * TODO The cache HotMap configuration should be set as a config option and + * not passed in through a setter. + */ public DfsBlockCacheConfig setCacheHotMap( Map<PackExt, Integer> cacheHotMap) { this.cacheHotMap = Collections.unmodifiableMap(cacheHotMap); + setCacheHotMapToPackExtConfigs(this.cacheHotMap); return this; } + private void setCacheHotMapToPackExtConfigs( + Map<PackExt, Integer> cacheHotMap) { + for (DfsBlockCachePackExtConfig packExtConfig : packExtCacheConfigurations) { + packExtConfig.setCacheHotMap(cacheHotMap); + } + } + /** * Get the consumer of cache index events. * @@ -240,61 +340,121 @@ public DfsBlockCacheConfig setIndexEventConsumer( } /** + * Get the list of pack ext cache configs. + * + * @return the list of pack ext cache configs. + */ + List<DfsBlockCachePackExtConfig> getPackExtCacheConfigurations() { + return packExtCacheConfigurations; + } + + /** + * Set the list of pack ext cache configs. + * + * Made visible for testing. + * + * @param packExtCacheConfigurations + * the list of pack ext cache configs to set. + * @return {@code this} + */ + DfsBlockCacheConfig setPackExtCacheConfigurations( + List<DfsBlockCachePackExtConfig> packExtCacheConfigurations) { + this.packExtCacheConfigurations = packExtCacheConfigurations; + return this; + } + + /** * Update properties by setting fields from the configuration. * <p> * If a property is not defined in the configuration, then it is left * unmodified. * <p> - * Enforces certain constraints on the combination of settings in the config, - * for example that the block limit is a multiple of the block size. + * Enforces certain constraints on the combination of settings in the + * config, for example that the block limit is a multiple of the block size. * * @param rc * configuration to read properties from. * @return {@code this} */ public DfsBlockCacheConfig fromConfig(Config rc) { - long cfgBlockLimit = rc.getLong( - CONFIG_CORE_SECTION, - CONFIG_DFS_SECTION, - CONFIG_KEY_BLOCK_LIMIT, - getBlockLimit()); - int cfgBlockSize = rc.getInt( - CONFIG_CORE_SECTION, - CONFIG_DFS_SECTION, - CONFIG_KEY_BLOCK_SIZE, + fromConfig(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, rc); + loadPackExtConfigs(rc); + return this; + } + + private void fromConfig(String section, String subSection, Config rc) { + long cfgBlockLimit = rc.getLong(section, subSection, + CONFIG_KEY_BLOCK_LIMIT, getBlockLimit()); + int cfgBlockSize = rc.getInt(section, subSection, CONFIG_KEY_BLOCK_SIZE, getBlockSize()); if (cfgBlockLimit % cfgBlockSize != 0) { throw new IllegalArgumentException(MessageFormat.format( JGitText.get().blockLimitNotMultipleOfBlockSize, - Long.valueOf(cfgBlockLimit), - Long.valueOf(cfgBlockSize))); + Long.valueOf(cfgBlockLimit), Long.valueOf(cfgBlockSize))); } + // Set name only if `core dfs` is configured, otherwise fall back to the + // default. + if (rc.getSubsections(section).contains(subSection)) { + this.name = subSection; + } setBlockLimit(cfgBlockLimit); setBlockSize(cfgBlockSize); - setConcurrencyLevel(rc.getInt( - CONFIG_CORE_SECTION, - CONFIG_DFS_SECTION, - CONFIG_KEY_CONCURRENCY_LEVEL, - getConcurrencyLevel())); + setConcurrencyLevel(rc.getInt(section, subSection, + CONFIG_KEY_CONCURRENCY_LEVEL, getConcurrencyLevel())); - String v = rc.getString( - CONFIG_CORE_SECTION, - CONFIG_DFS_SECTION, - CONFIG_KEY_STREAM_RATIO); + String v = rc.getString(section, subSection, CONFIG_KEY_STREAM_RATIO); if (v != null) { try { setStreamRatio(Double.parseDouble(v)); } catch (NumberFormatException e) { throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().enumValueNotSupported3, - CONFIG_CORE_SECTION, - CONFIG_DFS_SECTION, - CONFIG_KEY_STREAM_RATIO, v), e); + JGitText.get().enumValueNotSupported3, section, + subSection, CONFIG_KEY_STREAM_RATIO, v), e); } } - return this; + } + + private void loadPackExtConfigs(Config config) { + List<String> subSections = config.getSubsections(CONFIG_CORE_SECTION) + .stream() + .filter(section -> section.startsWith(CONFIG_DFS_CACHE_PREFIX)) + .collect(Collectors.toList()); + if (subSections.size() == 0) { + return; + } + ArrayList<DfsBlockCachePackExtConfig> cacheConfigs = new ArrayList<>(); + Set<PackExt> extensionsSeen = new HashSet<>(); + for (String subSection : subSections) { + var cacheConfig = DfsBlockCachePackExtConfig.fromConfig(config, + CONFIG_CORE_SECTION, subSection); + Set<PackExt> packExtsDuplicates = intersection(extensionsSeen, + cacheConfig.packExts); + if (packExtsDuplicates.size() > 0) { + String duplicatePackExts = packExtsDuplicates.stream() + .map(PackExt::toString) + .collect(Collectors.joining(",")); //$NON-NLS-1$ + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().duplicatePackExtensionsSet, + CONFIG_CORE_SECTION, subSection, + CONFIG_KEY_PACK_EXTENSIONS, duplicatePackExts)); + } + extensionsSeen.addAll(cacheConfig.packExts); + cacheConfigs.add(cacheConfig); + } + packExtCacheConfigurations = cacheConfigs; + setCacheHotMapToPackExtConfigs(this.cacheHotMap); + } + + private static <T> Set<T> intersection(Set<T> first, Set<T> second) { + Set<T> ret = new HashSet<>(); + for (T entry : second) { + if (first.contains(entry)) { + ret.add(entry); + } + } + return ret; } /** Consumer of DfsBlockCache loading and eviction events for indexes. */ @@ -346,4 +506,102 @@ default boolean shouldReportEvictedEvent() { return false; } } -} \ No newline at end of file + + /** + * A configuration for a single cache table storing 1 or more Pack + * extensions. + * <p> + * The current pack ext cache tables implementation supports the same + * parameters the ClockBlockCacheTable (current default implementation). + * <p> + * Configuration falls back to the defaults coded values defined in the + * {@link DfsBlockCacheConfig} when not set on each cache table + * configuration and NOT the values of the basic dfs section. + * <p> + * <code> + * + * Format: + * [core "dfs.packCache"] + * packExtensions = "PACK" + * blockSize = 512 + * blockLimit = 100 + * concurrencyLevel = 5 + * + * [core "dfs.multipleExtensionCache"] + * packExtensions = "INDEX REFTABLE BITMAP_INDEX" + * blockSize = 512 + * blockLimit = 100 + * concurrencyLevel = 5 + * </code> + */ + static class DfsBlockCachePackExtConfig { + // Set of pack extensions that will map to the cache instance. + private final EnumSet<PackExt> packExts; + + // Configuration for the cache instance. + private final DfsBlockCacheConfig packExtCacheConfiguration; + + /** + * Made visible for testing. + * + * @param packExts + * Set of {@link PackExt}s associated to this cache config. + * @param packExtCacheConfiguration + * {@link DfsBlockCacheConfig} for this cache config. + */ + DfsBlockCachePackExtConfig(EnumSet<PackExt> packExts, + DfsBlockCacheConfig packExtCacheConfiguration) { + this.packExts = packExts; + this.packExtCacheConfiguration = packExtCacheConfiguration; + } + + Set<PackExt> getPackExts() { + return packExts; + } + + DfsBlockCacheConfig getPackExtCacheConfiguration() { + return packExtCacheConfiguration; + } + + void setCacheHotMap(Map<PackExt, Integer> cacheHotMap) { + Map<PackExt, Integer> packExtHotMap = packExts.stream() + .filter(cacheHotMap::containsKey) + .collect(Collectors.toUnmodifiableMap(Function.identity(), + cacheHotMap::get)); + packExtCacheConfiguration.setCacheHotMap(packExtHotMap); + } + + private static DfsBlockCachePackExtConfig fromConfig(Config config, + String section, String subSection) { + String packExtensions = config.getString(section, subSection, + CONFIG_KEY_PACK_EXTENSIONS); + if (packExtensions == null) { + throw new IllegalArgumentException( + JGitText.get().noPackExtGivenForConfiguration); + } + String[] extensions = packExtensions.split(" ", -1); //$NON-NLS-1$ + Set<PackExt> packExts = new HashSet<>(extensions.length); + for (String extension : extensions) { + try { + packExts.add(PackExt.valueOf(extension)); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().unknownPackExtension, section, + subSection, CONFIG_KEY_PACK_EXTENSIONS, extension), + e); + } + } + + DfsBlockCacheConfig dfsBlockCacheConfig = new DfsBlockCacheConfig(); + dfsBlockCacheConfig.fromConfig(section, subSection, config); + return new DfsBlockCachePackExtConfig(EnumSet.copyOf(packExts), + dfsBlockCacheConfig); + } + + void print(String linePrefix, String pad, PrintWriter writer) { + packExtCacheConfiguration.print(linePrefix, pad, writer); + writer.println(linePrefix + pad + "PackExts: " //$NON-NLS-1$ + + packExts.stream().sorted().collect(Collectors.toList())); + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheStats.java new file mode 100644 index 0000000..436f574 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheStats.java
@@ -0,0 +1,197 @@ +/* + * Copyright (c) 2024, 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.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jgit.internal.storage.pack.PackExt; + +/** + * Keeps track of stats for a Block Cache table. + */ +class DfsBlockCacheStats implements BlockCacheStats { + private final String name; + + /** + * Number of times a block was found in the cache, per pack file extension. + */ + private final AtomicReference<AtomicLong[]> statHit; + + /** + * Number of times a block was not found, and had to be loaded, per pack + * file extension. + */ + private final AtomicReference<AtomicLong[]> statMiss; + + /** + * Number of blocks evicted due to cache being full, per pack file + * extension. + */ + private final AtomicReference<AtomicLong[]> statEvict; + + /** + * Number of bytes currently loaded in the cache, per pack file extension. + */ + private final AtomicReference<AtomicLong[]> liveBytes; + + DfsBlockCacheStats() { + this(""); //$NON-NLS-1$ + } + + DfsBlockCacheStats(String name) { + this.name = name; + statHit = new AtomicReference<>(newCounters()); + statMiss = new AtomicReference<>(newCounters()); + statEvict = new AtomicReference<>(newCounters()); + liveBytes = new AtomicReference<>(newCounters()); + } + + @Override + public String getName() { + return name; + } + + /** + * Increment the {@code statHit} count. + * + * @param key + * key identifying which liveBytes entry to update. + */ + void incrementHit(DfsStreamKey key) { + getStat(statHit, key).incrementAndGet(); + } + + /** + * Increment the {@code statMiss} count. + * + * @param key + * key identifying which liveBytes entry to update. + */ + void incrementMiss(DfsStreamKey key) { + getStat(statMiss, key).incrementAndGet(); + } + + /** + * Increment the {@code statEvict} count. + * + * @param key + * key identifying which liveBytes entry to update. + */ + void incrementEvict(DfsStreamKey key) { + getStat(statEvict, key).incrementAndGet(); + } + + /** + * Add {@code size} to the {@code liveBytes} count. + * + * @param key + * key identifying which liveBytes entry to update. + * @param size + * amount to increment the count by. + */ + void addToLiveBytes(DfsStreamKey key, long size) { + getStat(liveBytes, key).addAndGet(size); + } + + @Override + public long[] getCurrentSize() { + return getStatVals(liveBytes); + } + + @Override + public long[] getHitCount() { + return getStatVals(statHit); + } + + @Override + public long[] getMissCount() { + return getStatVals(statMiss); + } + + @Override + public long[] getTotalRequestCount() { + AtomicLong[] hit = statHit.get(); + AtomicLong[] miss = statMiss.get(); + long[] cnt = new long[Math.max(hit.length, miss.length)]; + for (int i = 0; i < hit.length; i++) { + cnt[i] += hit[i].get(); + } + for (int i = 0; i < miss.length; i++) { + cnt[i] += miss[i].get(); + } + return cnt; + } + + @Override + public long[] getHitRatio() { + AtomicLong[] hit = statHit.get(); + AtomicLong[] miss = statMiss.get(); + long[] ratio = new long[Math.max(hit.length, miss.length)]; + for (int i = 0; i < ratio.length; i++) { + if (i >= hit.length) { + ratio[i] = 0; + } else if (i >= miss.length) { + ratio[i] = 100; + } else { + long hitVal = hit[i].get(); + long missVal = miss[i].get(); + long total = hitVal + missVal; + ratio[i] = total == 0 ? 0 : hitVal * 100 / total; + } + } + return ratio; + } + + @Override + public long[] getEvictions() { + return getStatVals(statEvict); + } + + private static AtomicLong[] newCounters() { + AtomicLong[] ret = new AtomicLong[PackExt.values().length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = new AtomicLong(); + } + return ret; + } + + private static long[] getStatVals(AtomicReference<AtomicLong[]> stat) { + AtomicLong[] stats = stat.get(); + long[] cnt = new long[stats.length]; + for (int i = 0; i < stats.length; i++) { + cnt[i] = stats[i].get(); + } + return cnt; + } + + private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats, + DfsStreamKey key) { + int pos = key.packExtPos; + while (true) { + AtomicLong[] vals = stats.get(); + if (pos < vals.length) { + return vals[pos]; + } + AtomicLong[] expect = vals; + vals = new AtomicLong[Math.max(pos + 1, PackExt.values().length)]; + System.arraycopy(expect, 0, vals, 0, expect.length); + for (int i = expect.length; i < vals.length; i++) { + vals[i] = new AtomicLong(); + } + if (stats.compareAndSet(expect, vals)) { + return vals[pos]; + } + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java index 701d1fd..c3fd07b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java
@@ -11,10 +11,7 @@ package org.eclipse.jgit.internal.storage.dfs; import java.io.IOException; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jgit.internal.storage.pack.PackExt; +import java.util.List; /** * Block cache table. @@ -129,99 +126,43 @@ <T> DfsBlockCache.Ref<T> getOrLoadRef(DfsStreamKey key, long position, <T> T get(DfsStreamKey key, long position); /** - * Get the DfsBlockCacheStats object for this block cache table's - * statistics. + * Get the list of {@link BlockCacheStats} held by this cache. + * <p> + * The returned list has a {@link BlockCacheStats} per configured cache + * table, with a minimum of 1 {@link BlockCacheStats} object returned. * - * @return the DfsBlockCacheStats tracking this block cache table's - * statistics. + * Use {@link AggregatedBlockCacheStats} to combine the results of the stats + * in the list for an aggregated view of the cache's stats. + * + * @return the list of {@link BlockCacheStats} held by this cache. */ - DfsBlockCacheStats getDfsBlockCacheStats(); + List<BlockCacheStats> getBlockCacheStats(); /** - * Keeps track of stats for a Block Cache table. + * Get the name of the table. + * + * @return this table's name. */ - class DfsBlockCacheStats { - /** - * Number of times a block was found in the cache, per pack file - * extension. - */ - private final AtomicReference<AtomicLong[]> statHit; + String getName(); + + /** + * Provides methods used with Block Cache statistics. + */ + interface BlockCacheStats { /** - * Number of times a block was not found, and had to be loaded, per pack - * file extension. - */ - private final AtomicReference<AtomicLong[]> statMiss; - - /** - * Number of blocks evicted due to cache being full, per pack file - * extension. - */ - private final AtomicReference<AtomicLong[]> statEvict; - - /** - * Number of bytes currently loaded in the cache, per pack file - * extension. - */ - private final AtomicReference<AtomicLong[]> liveBytes; - - DfsBlockCacheStats() { - statHit = new AtomicReference<>(newCounters()); - statMiss = new AtomicReference<>(newCounters()); - statEvict = new AtomicReference<>(newCounters()); - liveBytes = new AtomicReference<>(newCounters()); - } - - /** - * Increment the {@code statHit} count. + * Get the name of the block cache generating this instance. * - * @param key - * key identifying which liveBytes entry to update. + * @return this cache's name. */ - void incrementHit(DfsStreamKey key) { - getStat(statHit, key).incrementAndGet(); - } - - /** - * Increment the {@code statMiss} count. - * - * @param key - * key identifying which liveBytes entry to update. - */ - void incrementMiss(DfsStreamKey key) { - getStat(statMiss, key).incrementAndGet(); - } - - /** - * Increment the {@code statEvict} count. - * - * @param key - * key identifying which liveBytes entry to update. - */ - void incrementEvict(DfsStreamKey key) { - getStat(statEvict, key).incrementAndGet(); - } - - /** - * Add {@code size} to the {@code liveBytes} count. - * - * @param key - * key identifying which liveBytes entry to update. - * @param size - * amount to increment the count by. - */ - void addToLiveBytes(DfsStreamKey key, long size) { - getStat(liveBytes, key).addAndGet(size); - } + String getName(); /** * Get total number of bytes in the cache, per pack file extension. * * @return total number of bytes in the cache, per pack file extension. */ - long[] getCurrentSize() { - return getStatVals(liveBytes); - } + long[] getCurrentSize(); /** * Get number of requests for items in the cache, per pack file @@ -230,9 +171,7 @@ void addToLiveBytes(DfsStreamKey key, long size) { * @return the number of requests for items in the cache, per pack file * extension. */ - long[] getHitCount() { - return getStatVals(statHit); - } + long[] getHitCount(); /** * Get number of requests for items not in the cache, per pack file @@ -241,9 +180,7 @@ void addToLiveBytes(DfsStreamKey key, long size) { * @return the number of requests for items not in the cache, per pack * file extension. */ - long[] getMissCount() { - return getStatVals(statMiss); - } + long[] getMissCount(); /** * Get total number of requests (hit + miss), per pack file extension. @@ -251,42 +188,14 @@ void addToLiveBytes(DfsStreamKey key, long size) { * @return total number of requests (hit + miss), per pack file * extension. */ - long[] getTotalRequestCount() { - AtomicLong[] hit = statHit.get(); - AtomicLong[] miss = statMiss.get(); - long[] cnt = new long[Math.max(hit.length, miss.length)]; - for (int i = 0; i < hit.length; i++) { - cnt[i] += hit[i].get(); - } - for (int i = 0; i < miss.length; i++) { - cnt[i] += miss[i].get(); - } - return cnt; - } + long[] getTotalRequestCount(); /** * Get hit ratios. * * @return hit ratios. */ - long[] getHitRatio() { - AtomicLong[] hit = statHit.get(); - AtomicLong[] miss = statMiss.get(); - long[] ratio = new long[Math.max(hit.length, miss.length)]; - for (int i = 0; i < ratio.length; i++) { - if (i >= hit.length) { - ratio[i] = 0; - } else if (i >= miss.length) { - ratio[i] = 100; - } else { - long hitVal = hit[i].get(); - long missVal = miss[i].get(); - long total = hitVal + missVal; - ratio[i] = total == 0 ? 0 : hitVal * 100 / total; - } - } - return ratio; - } + long[] getHitRatio(); /** * Get number of evictions performed due to cache being full, per pack @@ -295,46 +204,6 @@ void addToLiveBytes(DfsStreamKey key, long size) { * @return the number of evictions performed due to cache being full, * per pack file extension. */ - long[] getEvictions() { - return getStatVals(statEvict); - } - - private static AtomicLong[] newCounters() { - AtomicLong[] ret = new AtomicLong[PackExt.values().length]; - for (int i = 0; i < ret.length; i++) { - ret[i] = new AtomicLong(); - } - return ret; - } - - private static long[] getStatVals(AtomicReference<AtomicLong[]> stat) { - AtomicLong[] stats = stat.get(); - long[] cnt = new long[stats.length]; - for (int i = 0; i < stats.length; i++) { - cnt[i] = stats[i].get(); - } - return cnt; - } - - private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats, - DfsStreamKey key) { - int pos = key.packExtPos; - while (true) { - AtomicLong[] vals = stats.get(); - if (pos < vals.length) { - return vals[pos]; - } - AtomicLong[] expect = vals; - vals = new AtomicLong[Math.max(pos + 1, - PackExt.values().length)]; - System.arraycopy(expect, 0, vals, 0, expect.length); - for (int i = expect.length; i < vals.length; i++) { - vals[i] = new AtomicLong(); - } - if (stats.compareAndSet(expect, vals)) { - return vals[pos]; - } - } - } + long[] getEvictions(); } -} \ No newline at end of file +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java index a177669..199481c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
@@ -18,13 +18,13 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.internal.storage.dfs.DfsPackCompactor.configureReftable; import static org.eclipse.jgit.internal.storage.pack.PackExt.COMMIT_GRAPH; -import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -90,7 +90,7 @@ public class DfsGarbageCollector { private long coalesceGarbageLimit = 50 << 20; private long garbageTtlMillis = TimeUnit.DAYS.toMillis(1); - private long startTimeMillis; + private Instant startTime; private List<DfsPackFile> packsBefore; private List<DfsReftable> reftablesBefore; private List<DfsPackFile> expiredGarbagePacks; @@ -100,6 +100,7 @@ public class DfsGarbageCollector { private Set<ObjectId> allTags; private Set<ObjectId> nonHeads; private Set<ObjectId> tagTargets; + private Instant refLogExpire; /** * Initialize a garbage collector. @@ -200,6 +201,22 @@ public DfsGarbageCollector setReftableInitialMinUpdateIndex(long u) { return this; } + + /** + * Set time limit to the reflog history. + * <p> + * Garbage Collector prunes entries from reflog history older than {@code refLogExpire} + * <p> + * + * @param refLogExpire + * instant in time which defines refLog expiration + * @return {@code this} + */ + public DfsGarbageCollector setRefLogExpire(Instant refLogExpire) { + this.refLogExpire = refLogExpire; + return this; + } + /** * Set maxUpdateIndex for the initial reftable created during conversion. * @@ -335,7 +352,7 @@ public boolean pack(ProgressMonitor pm) throws IOException { throw new IllegalStateException( JGitText.get().supportOnlyPackIndexVersion2); - startTimeMillis = SystemReader.getInstance().getCurrentTime(); + startTime = SystemReader.getInstance().now(); ctx = objdb.newReader(); try { refdb.refresh(); @@ -418,7 +435,7 @@ private void readPacksBefore() throws IOException { packsBefore = new ArrayList<>(packs.length); expiredGarbagePacks = new ArrayList<>(packs.length); - long now = SystemReader.getInstance().getCurrentTime(); + long now = SystemReader.getInstance().now().toEpochMilli(); for (DfsPackFile p : packs) { DfsPackDescription d = p.getPackDescription(); if (d.getPackSource() != UNREACHABLE_GARBAGE) { @@ -687,14 +704,7 @@ private DfsPackDescription writePack(PackSource source, PackWriter pw, pack.setBlockSize(PACK, out.blockSize()); } - try (DfsOutputStream out = objdb.writeFile(pack, INDEX)) { - CountingOutputStream cnt = new CountingOutputStream(out); - pw.writeIndex(cnt); - pack.addFileExt(INDEX); - pack.setFileSize(INDEX, cnt.getCount()); - pack.setBlockSize(INDEX, out.blockSize()); - pack.setIndexVersion(pw.getIndexVersion()); - } + pw.writeIndex(objdb.getPackIndexWriter(pack, pw.getIndexVersion())); if (source != UNREACHABLE_GARBAGE && packConfig.getMinBytesForObjSizeIndex() >= 0) { try (DfsOutputStream out = objdb.writeFile(pack, @@ -713,7 +723,7 @@ private DfsPackDescription writePack(PackSource source, PackWriter pw, PackStatistics stats = pw.getStatistics(); pack.setPackStats(stats); - pack.setLastModified(startTimeMillis); + pack.setLastModified(startTime.toEpochMilli()); newPackDesc.add(pack); newPackStats.add(stats); newPackObj.add(pw.getObjectSet()); @@ -741,6 +751,10 @@ private void writeReftable(DfsPackDescription pack) throws IOException { compact.addAll(stack.readers()); compact.setIncludeDeletes(includeDeletes); compact.setConfig(configureReftable(reftableConfig, out)); + if(refLogExpire != null ){ + compact.setReflogExpireOldestReflogTimeMillis( + refLogExpire.toEpochMilli()); + } compact.compact(); pack.addFileExt(REFTABLE); pack.setReftableStats(compact.getStats());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java index a07d841..16315bf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -41,12 +41,13 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; import org.eclipse.jgit.internal.storage.file.PackIndex; -import org.eclipse.jgit.internal.storage.file.PackIndexWriter; import org.eclipse.jgit.internal.storage.file.PackObjectSizeIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdOwnerMap; @@ -54,7 +55,6 @@ import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectStream; -import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.PackedObjectInfo; import org.eclipse.jgit.util.BlockList; import org.eclipse.jgit.util.IO; @@ -71,6 +71,8 @@ public class DfsInserter extends ObjectInserter { private static final int INDEX_VERSION = 2; final DfsObjDatabase db; + + private final int minBytesForObjectSizeIndex; int compression = Deflater.BEST_COMPRESSION; List<PackedObjectInfo> objectList; @@ -83,8 +85,6 @@ public class DfsInserter extends ObjectInserter { private boolean rollback; private boolean checkExisting = true; - private int minBytesForObjectSizeIndex = -1; - /** * Initialize a new inserter. * @@ -93,8 +93,9 @@ public class DfsInserter extends ObjectInserter { */ protected DfsInserter(DfsObjDatabase db) { this.db = db; - PackConfig pc = new PackConfig(db.getRepository().getConfig()); - this.minBytesForObjectSizeIndex = pc.getMinBytesForObjSizeIndex(); + this.minBytesForObjectSizeIndex = db.getRepository().getConfig().getInt( + ConfigConstants.CONFIG_PACK_SECTION, + ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, -1); } /** @@ -112,21 +113,6 @@ public void checkExisting(boolean check) { void setCompressionLevel(int compression) { this.compression = compression; } - - /** - * Set minimum size for an object to be included in the object size index. - * - * <p> - * Use 0 for all and -1 for nothing (the pack won't have object size index). - * - * @param minBytes - * only objects with size bigger or equal to this are included in - * the index. - */ - protected void setMinBytesForObjectSizeIndex(int minBytes) { - this.minBytesForObjectSizeIndex = minBytes; - } - @Override public DfsPackParser newPackParser(InputStream in) throws IOException { return new DfsPackParser(db, this, in); @@ -333,7 +319,7 @@ PackIndex writePackIndex(DfsPackDescription pack, byte[] packHash, private static void index(OutputStream out, byte[] packHash, List<PackedObjectInfo> list) throws IOException { - PackIndexWriter.createVersion(out, INDEX_VERSION).write(list, packHash); + BasePackIndexWriter.createVersion(out, INDEX_VERSION).write(list, packHash); } void writeObjectSizeIndex(DfsPackDescription pack,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java index 616563f..efd666f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
@@ -12,6 +12,7 @@ import static java.util.stream.Collectors.joining; import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import java.io.FileNotFoundException; import java.io.IOException; @@ -27,7 +28,9 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; import org.eclipse.jgit.internal.storage.file.PackBitmapIndexWriterV1; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.lib.AnyObjectId; @@ -771,4 +774,35 @@ public PackBitmapIndexWriter getPackBitmapIndexWriter( } }; } + + /** + * Returns a writer to store the pack index in this object database. + * + * @param pack + * Pack file to which the index is associated. + * @param indexVersion + * which version of the index to write + * @return a writer to store the index associated with the pack + * @throws IOException + * when some I/O problem occurs while creating or writing to + * output stream + */ + public PackIndexWriter getPackIndexWriter( + DfsPackDescription pack, int indexVersion) + throws IOException { + return (objectsToStore, packDataChecksum) -> { + try (DfsOutputStream out = writeFile(pack, INDEX); + CountingOutputStream cnt = new CountingOutputStream(out)) { + final PackIndexWriter iw = BasePackIndexWriter + .createVersion(cnt, + indexVersion); + iw.write(objectsToStore, packDataChecksum); + pack.addFileExt(INDEX); + pack.setFileSize(INDEX, cnt.getCount()); + pack.setBlockSize(INDEX, out.blockSize()); + pack.setIndexVersion(indexVersion); + } + }; + } + }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java index 86144b3..f9c01b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -12,7 +12,7 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; -import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; import static org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation.PACK_DELTA; @@ -249,6 +249,7 @@ private void compactPacks(DfsReader ctx, ProgressMonitor pm) try { writePack(objdb, outDesc, pw, pm); writeIndex(objdb, outDesc, pw); + writeObjectSizeIndex(objdb, outDesc, pw); PackStatistics stats = pw.getStatistics(); @@ -458,13 +459,20 @@ private static void writePack(DfsObjDatabase objdb, private static void writeIndex(DfsObjDatabase objdb, DfsPackDescription pack, PackWriter pw) throws IOException { - try (DfsOutputStream out = objdb.writeFile(pack, INDEX)) { + pw.writeIndex(objdb.getPackIndexWriter(pack, pw.getIndexVersion())); + } + + private static void writeObjectSizeIndex(DfsObjDatabase objdb, + DfsPackDescription pack, + PackWriter pw) throws IOException { + try (DfsOutputStream out = objdb.writeFile(pack, OBJECT_SIZE_INDEX)) { CountingOutputStream cnt = new CountingOutputStream(out); - pw.writeIndex(cnt); - pack.addFileExt(INDEX); - pack.setFileSize(INDEX, cnt.getCount()); - pack.setBlockSize(INDEX, out.blockSize()); - pack.setIndexVersion(pw.getIndexVersion()); + pw.writeObjectSizeIndex(cnt); + if (cnt.getCount() > 0) { + pack.addFileExt(OBJECT_SIZE_INDEX); + pack.setFileSize(OBJECT_SIZE_INDEX, cnt.getCount()); + pack.setBlockSize(OBJECT_SIZE_INDEX, out.blockSize()); + } } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java index 5cc2a57..48ed47a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -29,6 +29,7 @@ import java.text.MessageFormat; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.zip.CRC32; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -106,6 +107,53 @@ public final class DfsPackFile extends BlockBasedFile { /** Lock for {@link #corruptObjects}. */ private final Object corruptObjectsLock = new Object(); + private final IndexFactory indexFactory; + + /** + * Returns the indexes for this pack. + * <p> + * We define indexes in different sub interfaces to allow implementing the + * indexes over different combinations of backends. + * <p> + * Implementations decide if/how to cache the indexes. The calling + * DfsPackFile will keep the reference to the index as long as it needs it. + */ + public interface IndexFactory { + /** + * Take care of loading the primary and reverse indexes for this pack. + */ + interface PackIndexes { + /** + * Load the primary index for the pack. + * + * @param ctx + * reader to find the raw bytes + * @return a primary index + * @throws IOException + * a problem finding/parsing the index + */ + PackIndex index(DfsReader ctx) throws IOException; + + /** + * Load the reverse index of the pack + * + * @param ctx + * reader to find the raw bytes + * @return the reverse index of the pack + * @throws IOException + * a problem finding/parsing the reverse index + */ + PackReverseIndex reverseIndex(DfsReader ctx) throws IOException; + } + + /** + * Returns a provider of the primary and reverse indexes of this pack + * + * @return an implementation of the {@link PackIndexes} interface + */ + PackIndexes getPackIndexes(); + } + /** * Construct a reader for an existing, packfile. * @@ -115,7 +163,8 @@ public final class DfsPackFile extends BlockBasedFile { * description of the pack within the DFS. */ DfsPackFile(DfsBlockCache cache, DfsPackDescription desc) { - this(cache, desc, DEFAULT_BITMAP_LOADER); + this(cache, desc, DEFAULT_BITMAP_LOADER, + new CachedStreamIndexFactory(cache, desc)); } /** @@ -127,9 +176,11 @@ public final class DfsPackFile extends BlockBasedFile { * description of the pack within the DFS * @param bitmapLoader * loader to get the bitmaps of this pack (if any) + * @param indexFactory + * an IndexFactory to get references to the indexes of this pack */ public DfsPackFile(DfsBlockCache cache, DfsPackDescription desc, - PackBitmapIndexLoader bitmapLoader) { + PackBitmapIndexLoader bitmapLoader, IndexFactory indexFactory) { super(cache, desc, PACK); int bs = desc.getBlockSize(PACK); @@ -141,6 +192,7 @@ public DfsPackFile(DfsBlockCache cache, DfsPackDescription desc, length = sz > 0 ? sz : -1; this.bitmapLoader = bitmapLoader; + this.indexFactory = indexFactory; } /** @@ -195,19 +247,10 @@ private PackIndex idx(DfsReader ctx) throws IOException { Repository.getGlobalListenerList() .dispatch(new BeforeDfsPackIndexLoadedEvent(this)); try { - DfsStreamKey idxKey = desc.getStreamKey(INDEX); - AtomicBoolean cacheHit = new AtomicBoolean(true); - DfsBlockCache.Ref<PackIndex> idxref = cache.getOrLoadRef(idxKey, - REF_POSITION, () -> { - cacheHit.set(false); - return loadPackIndex(ctx, idxKey); - }); - if (cacheHit.get()) { - ctx.stats.idxCacheHit++; - } - PackIndex idx = idxref.get(); - if (index == null && idx != null) { - index = idx; + index = indexFactory.getPackIndexes().index(ctx); + if (index == null) { + throw new IOException( + "Couldn't get a reference to the primary index"); //$NON-NLS-1$ } ctx.emitIndexLoad(desc, INDEX, index); return index; @@ -321,20 +364,10 @@ public PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException { return reverseIndex; } - PackIndex idx = idx(ctx); - DfsStreamKey revKey = desc.getStreamKey(REVERSE_INDEX); - AtomicBoolean cacheHit = new AtomicBoolean(true); - DfsBlockCache.Ref<PackReverseIndex> revref = cache.getOrLoadRef(revKey, - REF_POSITION, () -> { - cacheHit.set(false); - return loadReverseIdx(ctx, revKey, idx); - }); - if (cacheHit.get()) { - ctx.stats.ridxCacheHit++; - } - PackReverseIndex revidx = revref.get(); - if (reverseIndex == null && revidx != null) { - reverseIndex = revidx; + reverseIndex = indexFactory.getPackIndexes().reverseIndex(ctx); + if (reverseIndex == null) { + throw new IOException( + "Couldn't get a reference to the reverse index"); //$NON-NLS-1$ } ctx.emitIndexLoad(desc, REVERSE_INDEX, reverseIndex); return reverseIndex; @@ -347,6 +380,7 @@ private PackObjectSizeIndex getObjectSizeIndex(DfsReader ctx) } if (objectSizeIndexLoadAttempted + || !ctx.getOptions().shouldUseObjectSizeIndex() || !desc.hasFileExt(OBJECT_SIZE_INDEX)) { // Pack doesn't have object size index return null; @@ -1210,48 +1244,6 @@ private void setCorrupt(long offset) { } } - private DfsBlockCache.Ref<PackIndex> loadPackIndex( - DfsReader ctx, DfsStreamKey idxKey) throws IOException { - try { - ctx.stats.readIdx++; - long start = System.nanoTime(); - try (ReadableChannel rc = ctx.db.openFile(desc, INDEX)) { - PackIndex idx = PackIndex.read(alignTo8kBlocks(rc)); - ctx.stats.readIdxBytes += rc.position(); - index = idx; - return new DfsBlockCache.Ref<>( - idxKey, - REF_POSITION, - idx.getObjectCount() * REC_SIZE, - idx); - } finally { - ctx.stats.readIdxMicros += elapsedMicros(start); - } - } catch (EOFException e) { - throw new IOException(MessageFormat.format( - DfsText.get().shortReadOfIndex, - desc.getFileName(INDEX)), e); - } catch (IOException e) { - throw new IOException(MessageFormat.format( - DfsText.get().cannotReadIndex, - desc.getFileName(INDEX)), e); - } - } - - private DfsBlockCache.Ref<PackReverseIndex> loadReverseIdx( - DfsReader ctx, DfsStreamKey revKey, PackIndex idx) { - ctx.stats.readReverseIdx++; - long start = System.nanoTime(); - PackReverseIndex revidx = PackReverseIndexFactory.computeFromIndex(idx); - reverseIndex = revidx; - ctx.stats.readReverseIdxMicros += elapsedMicros(start); - return new DfsBlockCache.Ref<>( - revKey, - REF_POSITION, - idx.getObjectCount() * 8, - revidx); - } - private DfsBlockCache.Ref<PackObjectSizeIndex> loadObjectSizeIndex( DfsReader ctx, DfsStreamKey objectSizeIndexKey) throws IOException { ctx.stats.readObjectSizeIndex++; @@ -1288,9 +1280,12 @@ private DfsBlockCache.Ref<PackObjectSizeIndex> loadObjectSizeIndex( private DfsBlockCache.Ref<PackBitmapIndex> loadBitmapIndex(DfsReader ctx, DfsStreamKey bitmapKey) throws IOException { ctx.stats.readBitmap++; + long start = System.nanoTime(); PackBitmapIndexLoader.LoadResult result = bitmapLoader .loadPackBitmapIndex(ctx, this); bitmapIndex = result.bitmapIndex; + ctx.stats.readBitmapIdxBytes += result.bytesRead; + ctx.stats.readBitmapIdxMicros += elapsedMicros(start); return new DfsBlockCache.Ref<>(bitmapKey, REF_POSITION, result.bytesRead, result.bitmapIndex); } @@ -1449,4 +1444,141 @@ public LoadResult loadPackBitmapIndex(DfsReader ctx, DfsPackFile pack) } } } + + /** + * An index factory backed by Dfs streams and references cached in + * DfsBlockCache + */ + public static final class CachedStreamIndexFactory implements IndexFactory { + private final CachedStreamPackIndexes indexes; + + /** + * An index factory + * + * @param cache + * DFS block cache to use for the references + * @param desc + * This factory loads indexes for this package + */ + public CachedStreamIndexFactory(DfsBlockCache cache, + DfsPackDescription desc) { + this.indexes = new CachedStreamPackIndexes(cache, desc); + } + + @Override + public PackIndexes getPackIndexes() { + return indexes; + } + } + + /** + * Load primary and reverse index from Dfs streams and cache the references + * in DfsBlockCache. + */ + public static final class CachedStreamPackIndexes implements IndexFactory.PackIndexes { + private final DfsBlockCache cache; + + private final DfsPackDescription desc; + + /** + * An index factory + * + * @param cache + * DFS block cache to use for the references + * @param desc This factory loads indexes for this package + */ + public CachedStreamPackIndexes(DfsBlockCache cache, + DfsPackDescription desc) { + this.cache = cache; + this.desc = desc; + } + + @Override + public PackIndex index(DfsReader ctx) throws IOException { + DfsStreamKey idxKey = desc.getStreamKey(INDEX); + // Keep the value parsed in the loader, in case the Ref<> is + // nullified in ClockBlockCacheTable#reserveSpace + // before we read its value. + AtomicReference<PackIndex> loadedRef = new AtomicReference<>(null); + DfsBlockCache.Ref<PackIndex> cachedRef = cache.getOrLoadRef(idxKey, + REF_POSITION, () -> { + RefWithSize<PackIndex> idx = loadPackIndex(ctx, desc); + loadedRef.set(idx.ref); + return new DfsBlockCache.Ref<>(idxKey, REF_POSITION, + idx.size, idx.ref); + }); + if (loadedRef.get() == null) { + ctx.stats.idxCacheHit++; + } + return cachedRef.get() != null ? cachedRef.get() : loadedRef.get(); + } + + private static RefWithSize<PackIndex> loadPackIndex(DfsReader ctx, + DfsPackDescription desc) throws IOException { + try { + ctx.stats.readIdx++; + long start = System.nanoTime(); + try (ReadableChannel rc = ctx.db.openFile(desc, INDEX)) { + PackIndex idx = PackIndex.read(alignTo8kBlocks(rc)); + ctx.stats.readIdxBytes += rc.position(); + return new RefWithSize<>(idx, + idx.getObjectCount() * REC_SIZE); + } finally { + ctx.stats.readIdxMicros += elapsedMicros(start); + } + } catch (EOFException e) { + throw new IOException( + MessageFormat.format(DfsText.get().shortReadOfIndex, + desc.getFileName(INDEX)), + e); + } catch (IOException e) { + throw new IOException( + MessageFormat.format(DfsText.get().cannotReadIndex, + desc.getFileName(INDEX)), + e); + } + } + + @Override + public PackReverseIndex reverseIndex(DfsReader ctx) throws IOException { + PackIndex idx = index(ctx); + DfsStreamKey revKey = desc.getStreamKey(REVERSE_INDEX); + // Keep the value parsed in the loader, in case the Ref<> is + // nullified in ClockBlockCacheTable#reserveSpace + // before we read its value. + AtomicReference<PackReverseIndex> loadedRef = new AtomicReference<>( + null); + DfsBlockCache.Ref<PackReverseIndex> cachedRef = cache + .getOrLoadRef(revKey, REF_POSITION, () -> { + RefWithSize<PackReverseIndex> ridx = loadReverseIdx(ctx, + idx); + loadedRef.set(ridx.ref); + return new DfsBlockCache.Ref<>(revKey, REF_POSITION, + ridx.size, ridx.ref); + }); + if (loadedRef.get() == null) { + ctx.stats.ridxCacheHit++; + } + return cachedRef.get() != null ? cachedRef.get() : loadedRef.get(); + } + + private static RefWithSize<PackReverseIndex> loadReverseIdx( + DfsReader ctx, PackIndex idx) { + ctx.stats.readReverseIdx++; + long start = System.nanoTime(); + PackReverseIndex revidx = PackReverseIndexFactory + .computeFromIndex(idx); + ctx.stats.readReverseIdxMicros += elapsedMicros(start); + return new RefWithSize<>(revidx, idx.getObjectCount() * 8); + } + } + + private static final class RefWithSize<V> { + final V ref; + final long size; + RefWithSize(V ref, long size) { + this.ref = ref; + this.size = size; + } + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java index c939114..62f6753 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -307,7 +307,7 @@ private static class FoundObject<T extends ObjectId> { private <T extends ObjectId> Iterable<FoundObject<T>> findAll( Iterable<T> objectIds) throws IOException { - Collection<T> pending = new ArrayList<>(); + HashSet<T> pending = new HashSet<>(); for (T id : objectIds) { pending.add(id); } @@ -327,22 +327,21 @@ private <T extends ObjectId> Iterable<FoundObject<T>> findAll( } private <T extends ObjectId> void findAllImpl(PackList packList, - Collection<T> pending, List<FoundObject<T>> r) { + HashSet<T> pending, List<FoundObject<T>> r) { DfsPackFile[] packs = packList.packs; if (packs.length == 0) { return; } int lastIdx = 0; DfsPackFile lastPack = packs[lastIdx]; - - OBJECT_SCAN: for (Iterator<T> it = pending.iterator(); it.hasNext();) { - T t = it.next(); + HashSet<T> toRemove = new HashSet<>(); + OBJECT_SCAN: for (T t : pending) { if (!skipGarbagePack(lastPack)) { try { long p = lastPack.findOffset(this, t); if (0 < p) { r.add(new FoundObject<>(t, lastIdx, lastPack, p)); - it.remove(); + toRemove.add(t); continue; } } catch (IOException e) { @@ -360,7 +359,7 @@ private <T extends ObjectId> void findAllImpl(PackList packList, long p = pack.findOffset(this, t); if (0 < p) { r.add(new FoundObject<>(t, i, pack, p)); - it.remove(); + toRemove.add(t); lastIdx = i; lastPack = pack; continue OBJECT_SCAN; @@ -370,6 +369,7 @@ private <T extends ObjectId> void findAllImpl(PackList packList, } } } + pending.removeAll(toRemove); last = lastPack; } @@ -511,18 +511,15 @@ public long getObjectSize(AnyObjectId objectId, int typeHint) throw new MissingObjectException(objectId.copy(), typeHint); } - if (typeHint != Constants.OBJ_BLOB || !pack.hasObjectSizeIndex(this)) { + if (typeHint != Constants.OBJ_BLOB || !safeHasObjectSizeIndex(pack)) { return pack.getObjectSize(this, objectId); } - long sz = pack.getIndexedObjectSize(this, objectId); + Optional<Long> maybeSz = safeGetIndexedObjectSize(pack, objectId); + long sz = maybeSz.orElse(-1L); if (sz >= 0) { - stats.objectSizeIndexHit += 1; return sz; } - - // Object wasn't in the index - stats.objectSizeIndexMiss += 1; return pack.getObjectSize(this, objectId); } @@ -541,23 +538,61 @@ public boolean isNotLargerThan(AnyObjectId objectId, int typeHint, } stats.isNotLargerThanCallCount += 1; - if (typeHint != Constants.OBJ_BLOB || !pack.hasObjectSizeIndex(this)) { + if (typeHint != Constants.OBJ_BLOB || !safeHasObjectSizeIndex(pack)) { return pack.getObjectSize(this, objectId) <= limit; } - long sz = pack.getIndexedObjectSize(this, objectId); + Optional<Long> maybeSz = safeGetIndexedObjectSize(pack, objectId); + if (maybeSz.isEmpty()) { + // Exception in object size index + return pack.getObjectSize(this, objectId) <= limit; + } + + long sz = maybeSz.get(); + if (sz >= 0) { + return sz <= limit; + } + + if (isLimitInsideIndexThreshold(pack, limit)) { + // With threshold T, not-found means object < T + // If limit L > T, then object < T < L + return true; + } + + return pack.getObjectSize(this, objectId) <= limit; + } + + private boolean safeHasObjectSizeIndex(DfsPackFile pack) { + try { + return pack.hasObjectSizeIndex(this); + } catch (IOException e) { + return false; + } + } + + private Optional<Long> safeGetIndexedObjectSize(DfsPackFile pack, + AnyObjectId objectId) { + long sz; + try { + sz = pack.getIndexedObjectSize(this, objectId); + } catch (IOException e) { + // Do not count the exception as an index miss + return Optional.empty(); + } if (sz < 0) { stats.objectSizeIndexMiss += 1; } else { stats.objectSizeIndexHit += 1; } + return Optional.of(sz); + } - // Got size from index or we didn't but we are sure it should be there. - if (sz >= 0 || pack.getObjectSizeIndexThreshold(this) <= limit) { - return sz <= limit; + private boolean isLimitInsideIndexThreshold(DfsPackFile pack, long limit) { + try { + return pack.getObjectSizeIndexThreshold(this) <= limit; + } catch (IOException e) { + return false; } - - return pack.getObjectSize(this, objectId) <= limit; } private DfsPackFile findPackWithObject(AnyObjectId objectId)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java index adb4673..fcfa3e0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
@@ -40,12 +40,12 @@ public static class Accumulator { /** Total number of complete pack indexes read into memory. */ long readIdx; - /** Total number of complete bitmap indexes read into memory. */ - long readBitmap; - /** Total number of reverse indexes added into memory. */ long readReverseIdx; + /** Total number of complete bitmap indexes read into memory. */ + long readBitmap; + /** Total number of complete commit graphs read into memory. */ long readCommitGraph; @@ -55,6 +55,9 @@ public static class Accumulator { /** Total number of bytes read from pack indexes. */ long readIdxBytes; + /** Total number of bytes read from bitmap indexes. */ + long readBitmapIdxBytes; + /** Total number of bytes read from commit graphs. */ long readCommitGraphBytes; @@ -67,18 +70,15 @@ public static class Accumulator { /** Total microseconds spent creating reverse indexes. */ long readReverseIdxMicros; + /** Total microseconds spent reading bitmap indexes. */ + long readBitmapIdxMicros; + /** Total microseconds spent creating commit graphs. */ long readCommitGraphMicros; /** Total microseconds spent creating object size indexes */ long readObjectSizeIndexMicros; - /** Total number of bytes read from bitmap indexes. */ - long readBitmapIdxBytes; - - /** Total microseconds spent reading bitmap indexes. */ - long readBitmapIdxMicros; - /** Total number of block cache hits. */ long blockCacheHit; @@ -195,15 +195,6 @@ public long getReadReverseIndexCount() { } /** - * Get total number of times the commit graph read into memory. - * - * @return total number of commit graph read into memory. - */ - public long getReadCommitGraphCount() { - return stats.readCommitGraph; - } - - /** * Get total number of complete bitmap indexes read into memory. * * @return total number of complete bitmap indexes read into memory. @@ -213,6 +204,15 @@ public long getReadBitmapIndexCount() { } /** + * Get total number of times the commit graph read into memory. + * + * @return total number of commit graph read into memory. + */ + public long getReadCommitGraphCount() { + return stats.readCommitGraph; + } + + /** * Get total number of complete object size indexes read into memory. * * @return total number of complete object size indexes read into memory. @@ -231,6 +231,15 @@ public long getReadIndexBytes() { } /** + * Get total number of bytes read from bitmap indexes. + * + * @return total number of bytes read from bitmap indexes. + */ + public long getReadBitmapIndexBytes() { + return stats.readBitmapIdxBytes; + } + + /** * Get total number of bytes read from commit graphs. * * @return total number of bytes read from commit graphs. @@ -240,6 +249,15 @@ public long getCommitGraphBytes() { } /** + * Get total number of bytes read from object size indexes. + * + * @return total number of bytes read from object size indexes. + */ + public long getObjectSizeIndexBytes() { + return stats.readObjectSizeIndexBytes; + } + + /** * Get total microseconds spent reading pack indexes. * * @return total microseconds spent reading pack indexes. @@ -258,6 +276,15 @@ public long getReadReverseIndexMicros() { } /** + * Get total microseconds spent reading bitmap indexes. + * + * @return total microseconds spent reading bitmap indexes. + */ + public long getReadBitmapIndexMicros() { + return stats.readBitmapIdxMicros; + } + + /** * Get total microseconds spent reading commit graphs. * * @return total microseconds spent reading commit graphs. @@ -267,21 +294,12 @@ public long getReadCommitGraphMicros() { } /** - * Get total number of bytes read from bitmap indexes. + * Get total microseconds spent reading object size indexes. * - * @return total number of bytes read from bitmap indexes. + * @return total microseconds spent reading object size indexes. */ - public long getReadBitmapIndexBytes() { - return stats.readBitmapIdxBytes; - } - - /** - * Get total microseconds spent reading bitmap indexes. - * - * @return total microseconds spent reading bitmap indexes. - */ - public long getReadBitmapIndexMicros() { - return stats.readBitmapIdxMicros; + public long getReadObjectSizeIndexMicros() { + return stats.readObjectSizeIndexMicros; } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java index f2ac461..c397469 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java
@@ -13,8 +13,10 @@ import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_DELTA_BASE_CACHE_LIMIT; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_LOAD_REV_INDEX_IN_PARALLEL; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_BUFFER; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_FILE_THRESHOLD; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_USE_OBJECT_SIZE_INDEX; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.storage.pack.PackConfig; @@ -36,6 +38,8 @@ public class DfsReaderOptions { private boolean loadRevIndexInParallel; + private boolean useObjectSizeIndex; + /** * Create a default reader configuration. */ @@ -137,6 +141,28 @@ public DfsReaderOptions setLoadRevIndexInParallel( } /** + * Use the object size index if available. + * + * @return true if the reader should try to use the object size index. if + * false, the reader ignores that index. + */ + public boolean shouldUseObjectSizeIndex() { + return useObjectSizeIndex; + } + + /** + * Set if the reader should try to use the object size index + * + * @param useObjectSizeIndex true to use it, false to ignore the object size index + * + * @return {@code this} + */ + public DfsReaderOptions setUseObjectSizeIndex(boolean useObjectSizeIndex) { + this.useObjectSizeIndex = useObjectSizeIndex; + return this; + } + + /** * Update properties by setting fields from the configuration. * <p> * If a property is not defined in the configuration, then it is left @@ -168,6 +194,13 @@ public DfsReaderOptions fromConfig(Config rc) { CONFIG_DFS_SECTION, CONFIG_KEY_STREAM_BUFFER, getStreamPackBufferSize())); + + setUseObjectSizeIndex(rc.getBoolean(CONFIG_CORE_SECTION, + CONFIG_DFS_SECTION, CONFIG_KEY_USE_OBJECT_SIZE_INDEX, + false)); + setLoadRevIndexInParallel( + rc.getBoolean(CONFIG_CORE_SECTION, CONFIG_DFS_SECTION, + CONFIG_KEY_LOAD_REV_INDEX_IN_PARALLEL, false)); return this; } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java index 3ba74b2..2751cd2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java
@@ -28,6 +28,7 @@ import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.util.RefList; @@ -177,6 +178,11 @@ public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> exclu } @Override + public ReflogReader getReflogReader(Ref ref) throws IOException { + return reftableDatabase.getReflogReader(ref.getName()); + } + + @Override public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException { if (!getReftableConfig().isIndexObjects()) { return super.getTipsWithSha1(id);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java new file mode 100644 index 0000000..bb44f93 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java
@@ -0,0 +1,215 @@ +/* + * Copyright (c) 2024, 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.text.MessageFormat; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCache.ReadableChannelSupplier; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCache.Ref; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCache.RefLoader; +import org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DfsBlockCachePackExtConfig; +import org.eclipse.jgit.internal.storage.pack.PackExt; + +/** + * A table that holds multiple cache tables accessed by {@link PackExt} types. + * + * <p> + * Allows the separation of entries from different {@link PackExt} types to + * limit churn in cache caused by entries of differing sizes. + * <p> + * Separating these tables enables the fine-tuning of cache tables per extension + * type. + */ +class PackExtBlockCacheTable implements DfsBlockCacheTable { + /** + * Table name. + */ + private final String name; + + private final DfsBlockCacheTable defaultBlockCacheTable; + + // Holds the unique tables backing the extBlockCacheTables values. + private final List<DfsBlockCacheTable> blockCacheTableList; + + // Holds the mapping of PackExt to DfsBlockCacheTables. + // The relation between the size of extBlockCacheTables entries and + // blockCacheTableList entries is: + // blockCacheTableList.size() <= extBlockCacheTables.size() + private final Map<PackExt, DfsBlockCacheTable> extBlockCacheTables; + + /** + * Builds the PackExtBlockCacheTable from a list of + * {@link DfsBlockCachePackExtConfig}s. + * + * @param cacheConfig + * {@link DfsBlockCacheConfig} containing + * {@link DfsBlockCachePackExtConfig}s used to configure + * PackExtBlockCacheTable. The {@link DfsBlockCacheConfig} holds + * the configuration for the default cache table. + * @return the cache table built from the given configs. + * @throws IllegalArgumentException + * when no {@link DfsBlockCachePackExtConfig} exists in the + * {@link DfsBlockCacheConfig}. + */ + static PackExtBlockCacheTable fromBlockCacheConfigs( + DfsBlockCacheConfig cacheConfig) { + DfsBlockCacheTable defaultTable = new ClockBlockCacheTable(cacheConfig); + Map<PackExt, DfsBlockCacheTable> packExtBlockCacheTables = new HashMap<>(); + List<DfsBlockCachePackExtConfig> packExtConfigs = cacheConfig + .getPackExtCacheConfigurations(); + if (packExtConfigs == null || packExtConfigs.size() == 0) { + throw new IllegalArgumentException( + JGitText.get().noPackExtConfigurationGiven); + } + for (DfsBlockCachePackExtConfig packExtCacheConfig : packExtConfigs) { + DfsBlockCacheTable table = new ClockBlockCacheTable( + packExtCacheConfig.getPackExtCacheConfiguration()); + for (PackExt packExt : packExtCacheConfig.getPackExts()) { + if (packExtBlockCacheTables.containsKey(packExt)) { + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().duplicatePackExtensionsForCacheTables, + packExt)); + } + packExtBlockCacheTables.put(packExt, table); + } + } + return fromCacheTables(defaultTable, packExtBlockCacheTables); + } + + /** + * Creates a new PackExtBlockCacheTable from the combination of a default + * {@link DfsBlockCacheTable} and a map of {@link PackExt}s to + * {@link DfsBlockCacheTable}s. + * <p> + * This method allows for the PackExtBlockCacheTable to handle a mapping of + * {@link PackExt}s to arbitrarily defined {@link DfsBlockCacheTable} + * implementations. This is especially useful for users wishing to implement + * custom cache tables. + * <p> + * This is currently made visible for testing. + * + * @param defaultBlockCacheTable + * the default table used when a handling a {@link PackExt} type + * that does not map to a {@link DfsBlockCacheTable} mapped by + * packExtsCacheTablePairs. + * @param packExtBlockCacheTables + * the mapping of {@link PackExt}s to + * {@link DfsBlockCacheTable}s. A single + * {@link DfsBlockCacheTable} can be defined for multiple + * {@link PackExt}s in a many-to-one relationship. + * @return the PackExtBlockCacheTable created from the + * defaultBlockCacheTable and packExtsCacheTablePairs mapping. + * @throws IllegalArgumentException + * when a {@link PackExt} is defined for multiple + * {@link DfsBlockCacheTable}s. + */ + static PackExtBlockCacheTable fromCacheTables( + DfsBlockCacheTable defaultBlockCacheTable, + Map<PackExt, DfsBlockCacheTable> packExtBlockCacheTables) { + Set<DfsBlockCacheTable> blockCacheTables = new HashSet<>(); + blockCacheTables.add(defaultBlockCacheTable); + blockCacheTables.addAll(packExtBlockCacheTables.values()); + String name = defaultBlockCacheTable.getName() + "," //$NON-NLS-1$ + + packExtBlockCacheTables.values().stream() + .map(DfsBlockCacheTable::getName).sorted() + .collect(Collectors.joining(",")); //$NON-NLS-1$ + return new PackExtBlockCacheTable(name, defaultBlockCacheTable, + List.copyOf(blockCacheTables), packExtBlockCacheTables); + } + + private PackExtBlockCacheTable(String name, + DfsBlockCacheTable defaultBlockCacheTable, + List<DfsBlockCacheTable> blockCacheTableList, + Map<PackExt, DfsBlockCacheTable> extBlockCacheTables) { + this.name = name; + this.defaultBlockCacheTable = defaultBlockCacheTable; + this.blockCacheTableList = blockCacheTableList; + this.extBlockCacheTables = extBlockCacheTables; + } + + @Override + public boolean hasBlock0(DfsStreamKey key) { + return getTable(key).hasBlock0(key); + } + + @Override + public DfsBlock getOrLoad(BlockBasedFile file, long position, + DfsReader dfsReader, ReadableChannelSupplier fileChannel) + throws IOException { + return getTable(file.ext).getOrLoad(file, position, dfsReader, + fileChannel); + } + + @Override + public <T> Ref<T> getOrLoadRef(DfsStreamKey key, long position, + RefLoader<T> loader) throws IOException { + return getTable(key).getOrLoadRef(key, position, loader); + } + + @Override + public void put(DfsBlock v) { + getTable(v.stream).put(v); + } + + @Override + public <T> Ref<T> put(DfsStreamKey key, long pos, long size, T v) { + return getTable(key).put(key, pos, size, v); + } + + @Override + public <T> Ref<T> putRef(DfsStreamKey key, long size, T v) { + return getTable(key).putRef(key, size, v); + } + + @Override + public boolean contains(DfsStreamKey key, long position) { + return getTable(key).contains(key, position); + } + + @Override + public <T> T get(DfsStreamKey key, long position) { + return getTable(key).get(key, position); + } + + @Override + public List<BlockCacheStats> getBlockCacheStats() { + return blockCacheTableList.stream() + .flatMap(cacheTable -> cacheTable.getBlockCacheStats().stream()) + .collect(Collectors.toList()); + } + + @Override + public String getName() { + return name; + } + + private DfsBlockCacheTable getTable(PackExt packExt) { + return extBlockCacheTables.getOrDefault(packExt, + defaultBlockCacheTable); + } + + private DfsBlockCacheTable getTable(DfsStreamKey key) { + return extBlockCacheTables.getOrDefault(getPackExt(key), + defaultBlockCacheTable); + } + + private static PackExt getPackExt(DfsStreamKey key) { + return PackExt.values()[key.packExtPos]; + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackIndexWriter.java similarity index 97% rename from org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java rename to org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackIndexWriter.java index 87e0b44..b89cc1e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BasePackIndexWriter.java
@@ -19,6 +19,7 @@ import java.util.List; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.transport.PackedObjectInfo; import org.eclipse.jgit.util.NB; @@ -31,7 +32,7 @@ * random access to any object in the pack by associating an ObjectId to the * byte offset within the pack where the object's data can be read. */ -public abstract class PackIndexWriter { +public abstract class BasePackIndexWriter implements PackIndexWriter { /** Magic constant indicating post-version 1 format. */ protected static final byte[] TOC = { -1, 't', 'O', 'c' }; @@ -147,7 +148,7 @@ public static PackIndexWriter createVersion(final OutputStream dst, * the stream this instance outputs to. If not already buffered * it will be automatically wrapped in a buffered stream. */ - protected PackIndexWriter(OutputStream dst) { + protected BasePackIndexWriter(OutputStream dst) { out = new DigestOutputStream(dst instanceof BufferedOutputStream ? dst : new BufferedOutputStream(dst), Constants.newMessageDigest()); @@ -172,6 +173,7 @@ protected PackIndexWriter(OutputStream dst) { * an error occurred while writing to the output stream, or this * index format cannot store the object data supplied. */ + @Override public void write(final List<? extends PackedObjectInfo> toStore, final byte[] packDataChecksum) throws IOException { entries = toStore;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java index ed2516d..e9782e2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
@@ -16,6 +16,7 @@ import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -23,22 +24,27 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.PackRefsCommand; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.events.RefsChangedEvent; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.reftable.MergedReftable; import org.eclipse.jgit.internal.storage.reftable.ReftableBatchRefUpdate; import org.eclipse.jgit.internal.storage.reftable.ReftableDatabase; import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefRename; @@ -67,15 +73,20 @@ public class FileReftableDatabase extends RefDatabase { private final FileReftableStack reftableStack; + private final AtomicBoolean autoRefresh; + FileReftableDatabase(FileRepository repo) throws IOException { - this(repo, new File(new File(repo.getDirectory(), Constants.REFTABLE), + this(repo, new File(new File(repo.getCommonDirectory(), Constants.REFTABLE), Constants.TABLES_LIST)); } FileReftableDatabase(FileRepository repo, File refstackName) throws IOException { this.fileRepository = repo; + this.autoRefresh = new AtomicBoolean(repo.getConfig().getBoolean( + ConfigConstants.CONFIG_REFTABLE_SECTION, + ConfigConstants.CONFIG_KEY_AUTOREFRESH, false)); this.reftableStack = new FileReftableStack(refstackName, - new File(fileRepository.getDirectory(), Constants.REFTABLE), + new File(fileRepository.getCommonDirectory(), Constants.REFTABLE), () -> fileRepository.fireEvent(new RefsChangedEvent()), () -> fileRepository.getConfig()); this.reftableDatabase = new ReftableDatabase() { @@ -87,7 +98,13 @@ public MergedReftable openMergedReftable() throws IOException { }; } - ReflogReader getReflogReader(String refname) throws IOException { + @Override + public ReflogReader getReflogReader(Ref ref) throws IOException { + return reftableDatabase.getReflogReader(ref.getName()); + } + + @Override + public ReflogReader getReflogReader(String refname) throws IOException { return reftableDatabase.getReflogReader(refname); } @@ -108,6 +125,22 @@ public boolean hasFastTipsWithSha1() throws IOException { } /** + * {@inheritDoc} + * + * For Reftable, all the data is compacted into a single table. + */ + @Override + public void packRefs(ProgressMonitor pm, PackRefsCommand packRefs) + throws IOException { + pm.beginTask(JGitText.get().packRefs, 1); + try { + compactFully(); + } finally { + pm.endTask(); + } + } + + /** * Runs a full compaction for GC purposes. * @throws IOException on I/O errors */ @@ -158,6 +191,7 @@ public RefUpdate newUpdate(String refName, boolean detach) @Override public Ref exactRef(String name) throws IOException { + autoRefresh(); return reftableDatabase.exactRef(name); } @@ -168,6 +202,7 @@ public List<Ref> getRefs() throws IOException { @Override public Map<String, Ref> getRefs(String prefix) throws IOException { + autoRefresh(); List<Ref> refs = reftableDatabase.getRefsByPrefix(prefix); RefList.Builder<Ref> builder = new RefList.Builder<>(refs.size()); for (Ref r : refs) { @@ -180,6 +215,7 @@ public Map<String, Ref> getRefs(String prefix) throws IOException { @Override public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes) throws IOException { + autoRefresh(); return reftableDatabase.getRefsByPrefixWithExclusions(include, excludes); } @@ -198,6 +234,50 @@ public Ref peel(Ref ref) throws IOException { } + /** + * Whether to auto-refresh the reftable stack if it is out of date. + * + * @param autoRefresh + * whether to auto-refresh the reftable stack if it is out of + * date. + */ + public void setAutoRefresh(boolean autoRefresh) { + this.autoRefresh.set(autoRefresh); + } + + /** + * Whether the reftable stack is auto-refreshed if it is out of date. + * + * @return whether the reftable stack is auto-refreshed if it is out of + * date. + */ + public boolean isAutoRefresh() { + return autoRefresh.get(); + } + + private void autoRefresh() { + if (autoRefresh.get()) { + refresh(); + } + } + + /** + * Check if the reftable stack is up to date, and if not, reload it. + * <p> + * {@inheritDoc} + */ + @Override + public void refresh() { + try { + if (!reftableStack.isUpToDate()) { + reftableDatabase.clearCache(); + reftableStack.reload(); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + private Ref doPeel(Ref leaf) throws IOException { try (RevWalk rw = new RevWalk(fileRepository)) { RevObject obj = rw.parseAny(leaf.getObjectId()); @@ -318,7 +398,7 @@ public void close() { @Override public void create() throws IOException { FileUtils.mkdir( - new File(fileRepository.getDirectory(), Constants.REFTABLE), + new File(fileRepository.getCommonDirectory(), Constants.REFTABLE), true); } @@ -538,9 +618,10 @@ private static void writeConvertTable(Repository repo, ReftableWriter w, boolean writeLogs) throws IOException { int size = 0; List<Ref> refs = repo.getRefDatabase().getRefs(); + RefDatabase refDb = repo.getRefDatabase(); if (writeLogs) { for (Ref r : refs) { - ReflogReader rlr = repo.getReflogReader(r.getName()); + ReflogReader rlr = refDb.getReflogReader(r); if (rlr != null) { size = Math.max(rlr.getReverseEntries().size(), size); } @@ -563,10 +644,7 @@ private static void writeConvertTable(Repository repo, ReftableWriter w, if (writeLogs) { for (Ref r : refs) { long idx = size; - ReflogReader reader = repo.getReflogReader(r.getName()); - if (reader == null) { - continue; - } + ReflogReader reader = refDb.getReflogReader(r); for (ReflogEntry e : reader.getReverseEntries()) { w.writeLog(r.getName(), idx, e.getWho(), e.getOldId(), e.getNewId(), e.getComment()); @@ -615,7 +693,7 @@ public static FileReftableDatabase convertFrom(FileRepository repo, FileReftableDatabase newDb = null; File reftableList = null; try { - File reftableDir = new File(repo.getDirectory(), + File reftableDir = new File(repo.getCommonDirectory(), Constants.REFTABLE); reftableList = new File(reftableDir, Constants.TABLES_LIST); if (!reftableDir.isDirectory()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java index 0f5ff0f..b2c8892 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java
@@ -18,8 +18,10 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.StandardCopyOption; import java.security.SecureRandom; import java.util.ArrayList; @@ -27,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -39,6 +42,8 @@ import org.eclipse.jgit.internal.storage.reftable.ReftableReader; import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.TrustStat; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.SystemReader; @@ -59,6 +64,9 @@ private static class StackEntry { private List<StackEntry> stack; + private AtomicReference<FileSnapshot> snapshot = new AtomicReference<>( + FileSnapshot.DIRTY); + private long lastNextUpdateIndex; private final File stackPath; @@ -98,6 +106,8 @@ static class CompactionStats { private final CompactionStats stats; + private final TrustStat trustTablesListStat; + /** * Creates a stack corresponding to the list of reftables in the argument * @@ -126,6 +136,8 @@ public FileReftableStack(File stackPath, File reftableDir, reload(); stats = new CompactionStats(); + trustTablesListStat = configSupplier.get().get(CoreConfig.KEY) + .getTrustTablesListStat(); } CompactionStats getStats() { @@ -272,8 +284,9 @@ public interface Writer { } private List<String> readTableNames() throws IOException { + FileSnapshot old; List<String> names = new ArrayList<>(stack.size() + 1); - + old = snapshot.get(); try (BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream(stackPath), UTF_8))) { String line; @@ -282,8 +295,10 @@ private List<String> readTableNames() throws IOException { names.add(line); } } + snapshot.compareAndSet(old, FileSnapshot.save(stackPath)); } catch (FileNotFoundException e) { // file isn't there: empty repository. + snapshot.compareAndSet(old, FileSnapshot.MISSING_FILE); } return names; } @@ -294,9 +309,28 @@ private List<String> readTableNames() throws IOException { * on IO problem */ boolean isUpToDate() throws IOException { - // We could use FileSnapshot to avoid reading the file, but the file is - // small so it's probably a minor optimization. try { + switch (trustTablesListStat) { + case NEVER: + break; + case AFTER_OPEN: + try (InputStream stream = Files + .newInputStream(stackPath.toPath())) { + // open the tables.list file to refresh attributes (on some + // NFS clients) + } catch (FileNotFoundException | NoSuchFileException e) { + // ignore + } + //$FALL-THROUGH$ + case ALWAYS: + if (!snapshot.get().isModified(stackPath)) { + return true; + } + break; + case INHERIT: + // only used in CoreConfig internally + throw new IllegalStateException(); + } List<String> names = readTableNames(); if (names.size() != stack.size()) { return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index e5a00d3..bcf9f1e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -2,7 +2,7 @@ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2008-2010, Google Inc. * Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others + * Copyright (C) 2006-2024, 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 @@ -31,8 +31,8 @@ import java.util.Objects; import java.util.Set; -import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.attributes.AttributesNode; import org.eclipse.jgit.attributes.AttributesNodeProvider; @@ -60,7 +60,6 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; -import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; @@ -165,7 +164,7 @@ public FileRepository(BaseRepositoryBuilder options) throws IOException { throw new IOException(e.getMessage(), e); } repoConfig = new FileBasedConfig(userConfig, getFS().resolve( - getDirectory(), Constants.CONFIG), + getCommonDirectory(), Constants.CONFIG), getFS()); loadRepoConfig(); @@ -193,7 +192,7 @@ public FileRepository(BaseRepositoryBuilder options) throws IOException { options.getObjectDirectory(), // options.getAlternateObjectDirectories(), // getFS(), // - new File(getDirectory(), Constants.SHALLOW)); + new File(getCommonDirectory(), Constants.SHALLOW)); if (objectDatabase.exists()) { if (repositoryFormatVersion > 1) @@ -215,6 +214,16 @@ private void loadRepoConfig() throws IOException { } } + private String getRelativeDir(File base, File other) { + File relPath; + try { + relPath = base.toPath().relativize(other.toPath()).toFile(); + } catch (IllegalArgumentException e) { + relPath = other; + } + return FileUtils.pathToString(relPath); + } + /** * {@inheritDoc} * <p> @@ -223,6 +232,22 @@ private void loadRepoConfig() throws IOException { */ @Override public void create(boolean bare) throws IOException { + create(bare, false); + } + + /** + * Create a new Git repository initializing the necessary files and + * directories. + * + * @param bare + * if true, a bare repository (a repository without a working + * directory) is created. + * @param relativePaths + * if true, relative paths are used for GIT_DIR and GIT_WORK_TREE + * @throws IOException + * in case of IO problem + */ + public void create(boolean bare, boolean relativePaths) throws IOException { final FileBasedConfig cfg = getConfig(); if (cfg.getFile().exists()) { throw new IllegalStateException(MessageFormat.format( @@ -293,15 +318,25 @@ && getDirectory().getName().startsWith(".")) //$NON-NLS-1$ if (!bare) { File workTree = getWorkTree(); if (!getDirectory().getParentFile().equals(workTree)) { + String workTreePath; + String gitDirPath; + if (relativePaths) { + File canonGitDir = getDirectory().getCanonicalFile(); + File canonWorkTree = getWorkTree().getCanonicalFile(); + workTreePath = getRelativeDir(canonGitDir, canonWorkTree); + gitDirPath = getRelativeDir(canonWorkTree, canonGitDir); + } else { + workTreePath = getWorkTree().getAbsolutePath(); + gitDirPath = getDirectory().getAbsolutePath(); + } cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree() - .getAbsolutePath()); + ConfigConstants.CONFIG_KEY_WORKTREE, workTreePath); LockFile dotGitLockFile = new LockFile(new File(workTree, Constants.DOT_GIT)); try { if (dotGitLockFile.lock()) { dotGitLockFile.write(Constants.encode(Constants.GITDIR - + getDirectory().getAbsolutePath())); + + gitDirPath)); dotGitLockFile.commit(); } } finally { @@ -507,29 +542,6 @@ public void notifyIndexChanged(boolean internal) { } @Override - public ReflogReader getReflogReader(String refName) throws IOException { - if (refs instanceof FileReftableDatabase) { - // Cannot use findRef: reftable stores log data for deleted or renamed - // branches. - return ((FileReftableDatabase)refs).getReflogReader(refName); - } - - // TODO: use exactRef here, which offers more predictable and therefore preferable - // behavior. - Ref ref = findRef(refName); - if (ref == null) { - return null; - } - return new ReflogReaderImpl(this, ref.getName()); - } - - @Override - public @NonNull ReflogReader getReflogReader(@NonNull Ref ref) - throws IOException { - return new ReflogReaderImpl(this, ref.getName()); - } - - @Override public AttributesNodeProvider createAttributesNodeProvider() { return new AttributesNodeProviderImpl(this); } @@ -595,13 +607,12 @@ private boolean shouldAutoDetach() { @Override public void autoGC(ProgressMonitor monitor) { GC gc = new GC(this); - gc.setPackConfig(new PackConfig(this)); gc.setProgressMonitor(monitor); gc.setAuto(true); gc.setBackground(shouldAutoDetach()); try { gc.gc(); - } catch (ParseException | IOException e) { + } catch (ParseException | IOException | GitAPIException e) { throw new JGitInternalException(JGitText.get().gcFailed, e); } } @@ -622,16 +633,17 @@ public void autoGC(ProgressMonitor monitor) { * on IO problem */ void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException { + File commonDirectory = getCommonDirectory(); List<Ref> all = refs.getRefs(); - File packedRefs = new File(getDirectory(), Constants.PACKED_REFS); + File packedRefs = new File(commonDirectory, Constants.PACKED_REFS); if (packedRefs.exists()) { throw new IOException(MessageFormat.format(JGitText.get().fileAlreadyExists, packedRefs.getName())); } - File refsFile = new File(getDirectory(), "refs"); //$NON-NLS-1$ + File refsFile = new File(commonDirectory, "refs"); //$NON-NLS-1$ File refsHeadsFile = new File(refsFile, "heads");//$NON-NLS-1$ - File headFile = new File(getDirectory(), Constants.HEAD); + File headFile = new File(commonDirectory, Constants.HEAD); FileReftableDatabase oldDb = (FileReftableDatabase) refs; // Remove the dummy files that ensure compatibility with older git @@ -661,8 +673,8 @@ void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException { } if (writeLogs) { - List<ReflogEntry> logs = oldDb.getReflogReader(r.getName()) - .getReverseEntries(); + ReflogReader reflogReader = oldDb.getReflogReader(r); + List<ReflogEntry> logs = reflogReader.getReverseEntries(); Collections.reverse(logs); for (ReflogEntry e : logs) { logWriter.log(r.getName(), e); @@ -701,12 +713,14 @@ void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException { } if (!backup) { - File reftableDir = new File(getDirectory(), Constants.REFTABLE); + File reftableDir = new File(commonDirectory, Constants.REFTABLE); FileUtils.delete(reftableDir, FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS); } repoConfig.unset(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null, ConfigConstants.CONFIG_KEY_REF_STORAGE); + repoConfig.setLong(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0); repoConfig.save(); } @@ -730,8 +744,10 @@ void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException { @SuppressWarnings("nls") void convertToReftable(boolean writeLogs, boolean backup) throws IOException { - File reftableDir = new File(getDirectory(), Constants.REFTABLE); - File headFile = new File(getDirectory(), Constants.HEAD); + File commonDirectory = getCommonDirectory(); + File directory = getDirectory(); + File reftableDir = new File(commonDirectory, Constants.REFTABLE); + File headFile = new File(directory, Constants.HEAD); if (reftableDir.exists() && FileUtils.hasFiles(reftableDir.toPath())) { throw new IOException(JGitText.get().reftableDirExists); } @@ -739,28 +755,28 @@ void convertToReftable(boolean writeLogs, boolean backup) // Ignore return value, as it is tied to temporary newRefs file. FileReftableDatabase.convertFrom(this, writeLogs); - File refsFile = new File(getDirectory(), "refs"); + File refsFile = new File(commonDirectory, "refs"); // non-atomic: remove old data. - File packedRefs = new File(getDirectory(), Constants.PACKED_REFS); - File logsDir = new File(getDirectory(), Constants.LOGS); + File packedRefs = new File(commonDirectory, Constants.PACKED_REFS); + File logsDir = new File(commonDirectory, Constants.LOGS); List<String> additional = getRefDatabase().getAdditionalRefs().stream() .map(Ref::getName).collect(toList()); additional.add(Constants.HEAD); if (backup) { - FileUtils.rename(refsFile, new File(getDirectory(), "refs.old")); + FileUtils.rename(refsFile, new File(commonDirectory, "refs.old")); if (packedRefs.exists()) { - FileUtils.rename(packedRefs, new File(getDirectory(), + FileUtils.rename(packedRefs, new File(commonDirectory, Constants.PACKED_REFS + ".old")); } if (logsDir.exists()) { FileUtils.rename(logsDir, - new File(getDirectory(), Constants.LOGS + ".old")); + new File(commonDirectory, Constants.LOGS + ".old")); } for (String r : additional) { - FileUtils.rename(new File(getDirectory(), r), - new File(getDirectory(), r + ".old")); + FileUtils.rename(new File(commonDirectory, r), + new File(commonDirectory, r + ".old")); } } else { FileUtils.delete(packedRefs, FileUtils.SKIP_MISSING); @@ -770,7 +786,7 @@ void convertToReftable(boolean writeLogs, boolean backup) FileUtils.delete(refsFile, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING); for (String r : additional) { - new File(getDirectory(), r).delete(); + new File(commonDirectory, r).delete(); } } @@ -784,7 +800,7 @@ void convertToReftable(boolean writeLogs, boolean backup) // Some tools might write directly into .git/refs/heads/BRANCH. By // putting a file here, this fails spectacularly. - FileUtils.createNewFile(new File(refsFile, "heads")); + FileUtils.createNewFile(new File(refsFile, Constants.HEADS)); repoConfig.setString(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null, ConfigConstants.CONFIG_KEY_REF_STORAGE,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java index c88ac98..b6bde6e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java
@@ -15,6 +15,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.FileSystemException; import java.nio.file.NoSuchFileException; import java.nio.file.attribute.BasicFileAttributes; import java.time.Duration; @@ -22,10 +23,12 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Locale; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.TimeUnit; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS.FileStoreAttributes; import org.slf4j.Logger; @@ -139,29 +142,6 @@ private static Object getFileKey(BasicFileAttributes fileAttributes) { * @param modified * the last modification time of the file * @return the snapshot. - * @deprecated use {@link #save(Instant)} instead. - */ - @Deprecated - public static FileSnapshot save(long modified) { - final Instant read = Instant.now(); - return new FileSnapshot(read, Instant.ofEpochMilli(modified), - UNKNOWN_SIZE, FALLBACK_TIMESTAMP_RESOLUTION, MISSING_FILEKEY); - } - - /** - * Record a snapshot for a file for which the last modification time is - * already known. - * <p> - * This method should be invoked before the file is accessed. - * <p> - * Note that this method cannot rely on measuring file timestamp resolution - * to avoid racy git issues caused by finite file timestamp resolution since - * it's unknown in which filesystem the file is located. Hence the worst - * case fallback for timestamp resolution is used. - * - * @param modified - * the last modification time of the file - * @return the snapshot. */ public static FileSnapshot save(Instant modified) { final Instant read = Instant.now(); @@ -231,14 +211,8 @@ protected FileSnapshot(File file, boolean useConfig) { this.useConfig = useConfig; BasicFileAttributes fileAttributes = null; try { - fileAttributes = FS.DETECTED.fileAttributes(file); - } catch (NoSuchFileException e) { - this.lastModified = Instant.EPOCH; - this.size = 0L; - this.fileKey = MISSING_FILEKEY; - return; - } catch (IOException e) { - LOG.error(e.getMessage(), e); + fileAttributes = getFileAttributes(file); + } catch (NoSuchElementException e) { this.lastModified = Instant.EPOCH; this.size = 0L; this.fileKey = MISSING_FILEKEY; @@ -282,17 +256,6 @@ private FileSnapshot(Instant read, Instant modified, long size, * Get time of last snapshot update * * @return time of last snapshot update - * @deprecated use {@link #lastModifiedInstant()} instead - */ - @Deprecated - public long lastModified() { - return lastModified.toEpochMilli(); - } - - /** - * Get time of last snapshot update - * - * @return time of last snapshot update */ public Instant lastModifiedInstant() { return lastModified; @@ -319,16 +282,11 @@ public boolean isModified(File path) { long currSize; Object currFileKey; try { - BasicFileAttributes fileAttributes = FS.DETECTED.fileAttributes(path); + BasicFileAttributes fileAttributes = getFileAttributes(path); currLastModified = fileAttributes.lastModifiedTime().toInstant(); currSize = fileAttributes.size(); currFileKey = getFileKey(fileAttributes); - } catch (NoSuchFileException e) { - currLastModified = Instant.EPOCH; - currSize = 0L; - currFileKey = MISSING_FILEKEY; - } catch (IOException e) { - LOG.error(e.getMessage(), e); + } catch (NoSuchElementException e) { currLastModified = Instant.EPOCH; currSize = 0L; currFileKey = MISSING_FILEKEY; @@ -586,4 +544,27 @@ private FileStoreAttributes fileStoreAttributeCache() { } return fileStoreAttributeCache; } + + private static BasicFileAttributes getFileAttributes(File path) + throws NoSuchElementException { + try { + try { + return FS.DETECTED.fileAttributes(path); + } catch (IOException e) { + if (!FileUtils.isStaleFileHandle(e)) { + throw e; + } + } + } catch (NoSuchFileException e) { + // ignore + } catch (FileSystemException e) { + String msg = e.getMessage(); + if (!msg.endsWith("Not a directory")) { //$NON-NLS-1$ + LOG.error(msg, e); + } + } catch (IOException e) { + LOG.error(e.getMessage(), e); + } + throw new NoSuchElementException(path.toString()); + } }
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 cf26f8d..05bd970 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
@@ -63,6 +63,8 @@ import java.util.stream.Stream; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.PackRefsCommand; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.CancelledException; import org.eclipse.jgit.errors.CorruptObjectException; @@ -100,9 +102,8 @@ import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS.LockToken; import org.eclipse.jgit.util.FileUtils; -import org.eclipse.jgit.util.GitDateParser; +import org.eclipse.jgit.util.GitTimeParser; import org.eclipse.jgit.util.StringUtils; -import org.eclipse.jgit.util.SystemReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -158,11 +159,11 @@ public static void setExecutor(ExecutorService e) { private long expireAgeMillis = -1; - private Date expire; + private Instant expire; private long packExpireAgeMillis = -1; - private Date packExpire; + private Instant packExpire; private Boolean packKeptObjects; @@ -233,9 +234,11 @@ public GC(FileRepository repo) { * @throws java.text.ParseException * If the configuration parameter "gc.pruneexpire" couldn't be * parsed + * @throws GitAPIException + * If packing refs failed */ public CompletableFuture<Collection<Pack>> gc() - throws IOException, ParseException { + throws IOException, ParseException, GitAPIException { if (!background) { return CompletableFuture.completedFuture(doGc()); } @@ -254,7 +257,7 @@ public CompletableFuture<Collection<Pack>> gc() gcLog.commit(); } return newPacks; - } catch (IOException | ParseException e) { + } catch (IOException | ParseException | GitAPIException e) { try { gcLog.write(e.getMessage()); StringWriter sw = new StringWriter(); @@ -277,7 +280,8 @@ private ExecutorService executor() { return (executor != null) ? executor : WorkQueue.getExecutor(); } - private Collection<Pack> doGc() throws IOException, ParseException { + private Collection<Pack> doGc() + throws IOException, ParseException, GitAPIException { if (automatic && !needGc()) { return Collections.emptyList(); } @@ -286,7 +290,8 @@ private Collection<Pack> doGc() throws IOException, ParseException { return Collections.emptyList(); } pm.start(6 /* tasks */); - packRefs(); + new PackRefsCommand(repo).setProgressMonitor(pm).setAll(true) + .call(); // TODO: implement reflog_expire(pm, repo); Collection<Pack> newPacks = repack(); prune(Collections.emptySet()); @@ -692,16 +697,18 @@ private long getExpireDate() throws ParseException { if (expire == null && expireAgeMillis == -1) { String pruneExpireStr = getPruneExpireStr(); - if (pruneExpireStr == null) + if (pruneExpireStr == null) { pruneExpireStr = PRUNE_EXPIRE_DEFAULT; - expire = GitDateParser.parse(pruneExpireStr, null, SystemReader - .getInstance().getLocale()); + } + expire = GitTimeParser.parseInstant(pruneExpireStr); expireAgeMillis = -1; } - if (expire != null) - expireDate = expire.getTime(); - if (expireAgeMillis != -1) + if (expire != null) { + expireDate = expire.toEpochMilli(); + } + if (expireAgeMillis != -1) { expireDate = System.currentTimeMillis() - expireAgeMillis; + } return expireDate; } @@ -718,16 +725,18 @@ private long getPackExpireDate() throws ParseException { String prunePackExpireStr = repo.getConfig().getString( ConfigConstants.CONFIG_GC_SECTION, null, ConfigConstants.CONFIG_KEY_PRUNEPACKEXPIRE); - if (prunePackExpireStr == null) + if (prunePackExpireStr == null) { prunePackExpireStr = PRUNE_PACK_EXPIRE_DEFAULT; - packExpire = GitDateParser.parse(prunePackExpireStr, null, - SystemReader.getInstance().getLocale()); + } + packExpire = GitTimeParser.parseInstant(prunePackExpireStr); packExpireAgeMillis = -1; } - if (packExpire != null) - packExpireDate = packExpire.getTime(); - if (packExpireAgeMillis != -1) + if (packExpire != null) { + packExpireDate = packExpire.toEpochMilli(); + } + if (packExpireAgeMillis != -1) { packExpireDate = System.currentTimeMillis() - packExpireAgeMillis; + } return packExpireDate; } @@ -780,43 +789,6 @@ private static boolean equals(Ref r1, Ref r2) { } /** - * Pack ref storage. For a RefDirectory database, this packs all - * non-symbolic, loose refs into packed-refs. For Reftable, all of the data - * is compacted into a single table. - * - * @throws java.io.IOException - * if an IO error occurred - */ - public void packRefs() throws IOException { - RefDatabase refDb = repo.getRefDatabase(); - if (refDb instanceof FileReftableDatabase) { - // TODO: abstract this more cleanly. - pm.beginTask(JGitText.get().packRefs, 1); - try { - ((FileReftableDatabase) refDb).compactFully(); - } finally { - pm.endTask(); - } - return; - } - - Collection<Ref> refs = refDb.getRefsByPrefix(Constants.R_REFS); - List<String> refsToBePacked = new ArrayList<>(refs.size()); - pm.beginTask(JGitText.get().packRefs, refs.size()); - try { - for (Ref ref : refs) { - checkCancelled(); - if (!ref.isSymbolic() && ref.getStorage().isLoose()) - refsToBePacked.add(ref.getName()); - pm.update(1); - } - ((RefDirectory) repo.getRefDatabase()).pack(refsToBePacked); - } finally { - pm.endTask(); - } - } - - /** * Packs all objects which reachable from any of the heads into one pack * file. Additionally all objects which are not reachable from any head but * which are reachable from any of the other refs (e.g. tags), special refs @@ -1047,7 +1019,7 @@ private static boolean isTag(Ref ref) { } private void deleteEmptyRefsFolders() throws IOException { - Path refs = repo.getDirectory().toPath().resolve(Constants.R_REFS); + Path refs = repo.getCommonDirectory().toPath().resolve(Constants.R_REFS); // Avoid deleting a folder that was created after the threshold so that concurrent // operations trying to create a reference are not impacted Instant threshold = Instant.now().minus(30, ChronoUnit.SECONDS); @@ -1185,7 +1157,7 @@ private void deleteTempPacksIdx() { * if an IO error occurred */ private Set<ObjectId> listRefLogObjects(Ref ref, long minTime) throws IOException { - ReflogReader reflogReader = repo.getReflogReader(ref); + ReflogReader reflogReader = repo.getRefDatabase().getReflogReader(ref); List<ReflogEntry> rlEntries = reflogReader .getReverseEntries(); if (rlEntries == null || rlEntries.isEmpty()) @@ -1509,6 +1481,18 @@ public static class RepoStatistics { public long numberOfPackFiles; /** + * The number of pack files that were created since the last bitmap + * generation. + */ + public long numberOfPackFilesSinceBitmap; + + /** + * The number of objects stored in pack files and as loose object + * created after the last bitmap generation. + */ + public long numberOfObjectsSinceBitmap; + + /** * The number of objects stored as loose objects. */ public long numberOfLooseObjects; @@ -1543,6 +1527,10 @@ public String toString() { final StringBuilder b = new StringBuilder(); b.append("numberOfPackedObjects=").append(numberOfPackedObjects); //$NON-NLS-1$ b.append(", numberOfPackFiles=").append(numberOfPackFiles); //$NON-NLS-1$ + b.append(", numberOfPackFilesSinceBitmap=") //$NON-NLS-1$ + .append(numberOfPackFilesSinceBitmap); + b.append(", numberOfObjectsSinceBitmap=") //$NON-NLS-1$ + .append(numberOfObjectsSinceBitmap); b.append(", numberOfLooseObjects=").append(numberOfLooseObjects); //$NON-NLS-1$ b.append(", numberOfLooseRefs=").append(numberOfLooseRefs); //$NON-NLS-1$ b.append(", numberOfPackedRefs=").append(numberOfPackedRefs); //$NON-NLS-1$ @@ -1563,12 +1551,22 @@ public String toString() { public RepoStatistics getStatistics() throws IOException { RepoStatistics ret = new RepoStatistics(); Collection<Pack> packs = repo.getObjectDatabase().getPacks(); + long latestBitmapTime = 0L; for (Pack p : packs) { - ret.numberOfPackedObjects += p.getIndex().getObjectCount(); + long packedObjects = p.getIndex().getObjectCount(); + ret.numberOfPackedObjects += packedObjects; ret.numberOfPackFiles++; ret.sizeOfPackedObjects += p.getPackFile().length(); - if (p.getBitmapIndex() != null) + if (p.getBitmapIndex() != null) { ret.numberOfBitmaps += p.getBitmapIndex().getBitmapCount(); + if (latestBitmapTime == 0L) { + latestBitmapTime = p.getFileSnapshot().lastModifiedInstant().toEpochMilli(); + } + } + else if (latestBitmapTime == 0L) { + ret.numberOfPackFilesSinceBitmap++; + ret.numberOfObjectsSinceBitmap += packedObjects; + } } File objDir = repo.getObjectsDirectory(); String[] fanout = objDir.list(); @@ -1584,6 +1582,9 @@ public RepoStatistics getStatistics() throws IOException { continue; ret.numberOfLooseObjects++; ret.sizeOfLooseObjects += f.length(); + if (f.lastModified() > latestBitmapTime) { + ret.numberOfObjectsSinceBitmap ++; + } } } } @@ -1659,12 +1660,31 @@ public void setPackConfig(@NonNull PackConfig pconfig) { * candidate for pruning. * * @param expire - * instant in time which defines object expiration - * objects with modification time before this instant are expired - * objects with modification time newer or equal to this instant - * are not expired + * instant in time which defines object expiration objects with + * modification time before this instant are expired objects with + * modification time newer or equal to this instant are not + * expired + * @deprecated use {@link #setExpire(Instant)} instead */ + @Deprecated(since = "7.2") public void setExpire(Date expire) { + this.expire = expire.toInstant(); + expireAgeMillis = -1; + } + + /** + * During gc() or prune() each unreferenced, loose object which has been + * created or modified after or at <code>expire</code> will not be pruned. + * Only older objects may be pruned. If set to null then every object is a + * candidate for pruning. + * + * @param expire + * instant in time which defines object expiration objects with + * modification time before this instant are expired objects with + * modification time newer or equal to this instant are not + * expired + */ + public void setExpire(Instant expire) { this.expire = expire; expireAgeMillis = -1; } @@ -1677,8 +1697,24 @@ public void setExpire(Date expire) { * * @param packExpire * instant in time which defines packfile expiration + * @deprecated use {@link #setPackExpire(Instant)} instead */ + @Deprecated(since = "7.2") public void setPackExpire(Date packExpire) { + this.packExpire = packExpire.toInstant(); + packExpireAgeMillis = -1; + } + + /** + * During gc() or prune() packfiles which are created or modified after or + * at <code>packExpire</code> will not be deleted. Only older packfiles may + * be deleted. If set to null then every packfile is a candidate for + * deletion. + * + * @param packExpire + * instant in time which defines packfile expiration + */ + public void setPackExpire(Instant packExpire) { this.packExpire = packExpire; packExpireAgeMillis = -1; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java index 628bf5d..862aaab 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
@@ -23,8 +23,7 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.util.FileUtils; -import org.eclipse.jgit.util.GitDateParser; -import org.eclipse.jgit.util.SystemReader; +import org.eclipse.jgit.util.GitTimeParser; /** * This class manages the gc.log file for a {@link FileRepository}. @@ -50,7 +49,7 @@ class GcLog { */ GcLog(FileRepository repo) { this.repo = repo; - logFile = new File(repo.getDirectory(), "gc.log"); //$NON-NLS-1$ + logFile = new File(repo.getCommonDirectory(), "gc.log"); //$NON-NLS-1$ lock = new LockFile(logFile); } @@ -62,8 +61,7 @@ private Instant getLogExpiry() throws ParseException { if (logExpiryStr == null) { logExpiryStr = LOG_EXPIRY_DEFAULT; } - gcLogExpire = GitDateParser.parse(logExpiryStr, null, - SystemReader.getInstance().getLocale()).toInstant(); + gcLogExpire = GitTimeParser.parseInstant(logExpiryStr); } return gcLogExpire; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java index 11d842b..e8d442b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
@@ -46,7 +46,7 @@ public AttributesNode load() throws IOException { FS fs = repository.getFS(); - File attributes = fs.resolve(repository.getDirectory(), + File attributes = fs.resolve(repository.getCommonDirectory(), Constants.INFO_ATTRIBUTES); FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributes);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java index a2d8bd0..9e12ee8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
@@ -24,6 +24,7 @@ import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.FileTime; import java.text.MessageFormat; @@ -141,9 +142,8 @@ public boolean lock() throws IOException { throw new IllegalStateException( MessageFormat.format(JGitText.get().lockAlreadyHeld, ref)); } - FileUtils.mkdirs(lck.getParentFile(), true); try { - token = FS.DETECTED.createNewFileAtomic(lck); + token = createLockFileWithRetry(); } catch (IOException e) { LOG.error(JGitText.get().failedCreateLockFile, lck, e); throw e; @@ -160,6 +160,19 @@ public boolean lock() throws IOException { return obtainedLock; } + private FS.LockToken createLockFileWithRetry() throws IOException { + try { + return createLockFile(); + } catch (NoSuchFileException e) { + return createLockFile(); + } + } + + private FS.LockToken createLockFile() throws IOException { + FileUtils.mkdirs(lck.getParentFile(), true); + return FS.DETECTED.createNewFileAtomic(lck); + } + /** * Try to establish the lock for appending. * @@ -515,17 +528,6 @@ private void saveStatInformation() { * Get the modification time of the output file when it was committed. * * @return modification time of the lock file right before we committed it. - * @deprecated use {@link #getCommitLastModifiedInstant()} instead - */ - @Deprecated - public long getCommitLastModified() { - return commitSnapshot.lastModified(); - } - - /** - * Get the modification time of the output file when it was committed. - * - * @return modification time of the lock file right before we committed it. */ public Instant getCommitLastModifiedInstant() { return commitSnapshot.lastModifiedInstant();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java index b4bb2a9..909b3e3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java
@@ -26,8 +26,9 @@ import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.TrustStat; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.util.FileUtils; @@ -49,13 +50,13 @@ class LooseObjects { * Maximum number of attempts to read a loose object for which a stale file * handle exception is thrown */ - private final static int MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS = 5; + private final static int MAX_STALE_READ_RETRIES = 5; private final File directory; private final UnpackedObjectCache unpackedObjectCache; - private final boolean trustFolderStat; + private final TrustStat trustLooseObjectStat; /** * Initialize a reference to an on-disk object directory. @@ -68,9 +69,8 @@ class LooseObjects { LooseObjects(Config config, File dir) { directory = dir; unpackedObjectCache = new UnpackedObjectCache(); - trustFolderStat = config.getBoolean( - ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true); + trustLooseObjectStat = config.get(CoreConfig.KEY) + .getTrustLooseObjectStat(); } /** @@ -108,7 +108,8 @@ boolean hasCached(AnyObjectId id) { */ boolean has(AnyObjectId objectId) { boolean exists = hasWithoutRefresh(objectId); - if (trustFolderStat || exists) { + if (trustLooseObjectStat == TrustStat.ALWAYS + || exists) { return exists; } try (InputStream stream = Files.newInputStream(directory.toPath())) { @@ -163,13 +164,31 @@ boolean resolve(Set<ObjectId> matches, AbbreviatedObjectId id, } ObjectLoader open(WindowCursor curs, AnyObjectId id) throws IOException { - int readAttempts = 0; - while (readAttempts < MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS) { - readAttempts++; - File path = fileFor(id); - if (trustFolderStat && !path.exists()) { + File path = fileFor(id); + for (int retries = 0; retries < MAX_STALE_READ_RETRIES; retries++) { + boolean reload = true; + switch (trustLooseObjectStat) { + case NEVER: break; + case AFTER_OPEN: + try (InputStream stream = Files + .newInputStream(path.getParentFile().toPath())) { + // open the loose object's fanout directory to refresh + // attributes (on some NFS clients) + } catch (FileNotFoundException | NoSuchFileException e) { + // ignore + } + //$FALL-THROUGH$ + case ALWAYS: + if (!path.exists()) { + reload = false; + } + break; + case INHERIT: + // only used in CoreConfig internally + throw new IllegalStateException(); } + if (reload) { try { return getObjectLoader(curs, path, id); } catch (FileNotFoundException noFile) { @@ -183,9 +202,10 @@ ObjectLoader open(WindowCursor curs, AnyObjectId id) throws IOException { } if (LOG.isDebugEnabled()) { LOG.debug(MessageFormat.format( - JGitText.get().looseObjectHandleIsStale, id.name(), - Integer.valueOf(readAttempts), Integer.valueOf( - MAX_LOOSE_OBJECT_STALE_READ_ATTEMPTS))); + JGitText.get().looseObjectHandleIsStale, + id.name(), Integer.valueOf(retries), + Integer.valueOf(MAX_STALE_READ_RETRIES))); + } } } } @@ -211,7 +231,7 @@ ObjectLoader getObjectLoader(WindowCursor curs, File path, AnyObjectId id) try { return getObjectLoaderWithoutRefresh(curs, path, id); } catch (FileNotFoundException e) { - if (trustFolderStat) { + if (trustLooseObjectStat == TrustStat.ALWAYS) { throw e; } try (InputStream stream = Files @@ -248,7 +268,7 @@ long getSize(WindowCursor curs, AnyObjectId id) throws IOException { return getSizeWithoutRefresh(curs, id); } catch (FileNotFoundException noFile) { try { - if (trustFolderStat) { + if (trustLooseObjectStat == TrustStat.ALWAYS) { throw noFile; } try (InputStream stream = Files
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java index 9f27f4b..746e124 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
@@ -28,6 +28,7 @@ import org.eclipse.jgit.errors.LockFailedException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig; @@ -110,7 +111,7 @@ public class ObjectDirectoryPackParser extends PackParser { * @param version * the version to write. The special version 0 designates the * oldest (most compatible) format available for the objects. - * @see PackIndexWriter + * @see BasePackIndexWriter */ public void setIndexVersion(int version) { indexVersion = version; @@ -386,9 +387,9 @@ private void writeIdx() throws IOException { try (FileOutputStream os = new FileOutputStream(tmpIdx)) { final PackIndexWriter iw; if (indexVersion <= 0) - iw = PackIndexWriter.createOldestPossible(os, list); + iw = BasePackIndexWriter.createOldestPossible(os, list); else - iw = PackIndexWriter.createVersion(os, indexVersion); + iw = BasePackIndexWriter.createVersion(os, indexVersion); iw.write(list, packHash); os.getChannel().force(true); }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java index f87329c..5813d39 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -95,6 +95,9 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { private RandomAccessFile fd; + /** For managing open/close accounting of {@link #fd}. */ + private final Object activeLock = new Object(); + /** Serializes reads performed against {@link #fd}. */ private final Object readLock = new Object(); @@ -113,13 +116,13 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { private volatile Exception invalidatingCause; @Nullable - private PackFile bitmapIdxFile; + private volatile PackFile bitmapIdxFile; private AtomicInteger transientErrorCount = new AtomicInteger(); private byte[] packChecksum; - private volatile Optionally<PackIndex> loadedIdx = Optionally.empty(); + private Optionally<PackIndex> loadedIdx = Optionally.empty(); private Optionally<PackReverseIndex> reverseIdx = Optionally.empty(); @@ -159,60 +162,54 @@ public Pack(Config cfg, File packFile, @Nullable PackFile bitmapIdxFile) { length = Long.MAX_VALUE; } - private PackIndex idx() throws IOException { + private synchronized PackIndex idx() throws IOException { Optional<PackIndex> optional = loadedIdx.getOptional(); if (optional.isPresent()) { return optional.get(); } - synchronized (this) { - optional = loadedIdx.getOptional(); - if (optional.isPresent()) { - return optional.get(); + if (invalid) { + throw new PackInvalidException(packFile, invalidatingCause); + } + try { + long start = System.currentTimeMillis(); + PackFile idxFile = packFile.create(INDEX); + PackIndex idx = PackIndex.open(idxFile); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format( + "Opening pack index %s, size %.3f MB took %d ms", //$NON-NLS-1$ + idxFile.getAbsolutePath(), + Float.valueOf(idxFile.length() + / (1024f * 1024)), + Long.valueOf(System.currentTimeMillis() + - start))); } - if (invalid) { - throw new PackInvalidException(packFile, invalidatingCause); - } - try { - long start = System.currentTimeMillis(); - PackFile idxFile = packFile.create(INDEX); - PackIndex idx = PackIndex.open(idxFile); - if (LOG.isDebugEnabled()) { - LOG.debug(String.format( - "Opening pack index %s, size %.3f MB took %d ms", //$NON-NLS-1$ - idxFile.getAbsolutePath(), - Float.valueOf(idxFile.length() - / (1024f * 1024)), - Long.valueOf(System.currentTimeMillis() - - start))); - } - if (packChecksum == null) { - packChecksum = idx.packChecksum; - fileSnapshot.setChecksum( - ObjectId.fromRaw(packChecksum)); - } else if (!Arrays.equals(packChecksum, - idx.packChecksum)) { - throw new PackMismatchException(MessageFormat - .format(JGitText.get().packChecksumMismatch, - packFile.getPath(), - PackExt.PACK.getExtension(), - Hex.toHexString(packChecksum), - PackExt.INDEX.getExtension(), - Hex.toHexString(idx.packChecksum))); - } - loadedIdx = optionally(idx); - return idx; - } catch (InterruptedIOException e) { - // don't invalidate the pack, we are interrupted from - // another thread - throw e; - } catch (IOException e) { - invalid = true; - invalidatingCause = e; - throw e; + packChecksum = idx.getChecksum(); + fileSnapshot.setChecksum( + ObjectId.fromRaw(packChecksum)); + } else if (!Arrays.equals(packChecksum, + idx.getChecksum())) { + throw new PackMismatchException(MessageFormat + .format(JGitText.get().packChecksumMismatch, + packFile.getPath(), + PackExt.PACK.getExtension(), + Hex.toHexString(packChecksum), + PackExt.INDEX.getExtension(), + Hex.toHexString(idx.getChecksum()))); } + loadedIdx = optionally(idx); + return idx; + } catch (InterruptedIOException e) { + // don't invalidate the pack, we are interrupted from + // another thread + throw e; + } catch (IOException e) { + invalid = true; + invalidatingCause = e; + throw e; } } + /** * Get the File object which locates this pack on disk. * @@ -296,15 +293,28 @@ void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, int matchLimit) } /** - * Close the resources utilized by this repository + * Close the resources utilized by these pack files + * + * @param packs + * packs to close + */ + public static void close(Set<Pack> packs) { + WindowCache.purge(packs); + packs.forEach(p -> p.closeIndices()); + } + + /** + * Close the resources utilized by this pack file */ public void close() { WindowCache.purge(this); - synchronized (this) { - loadedIdx.clear(); - reverseIdx.clear(); - bitmapIdx.clear(); - } + closeIndices(); + } + + private synchronized void closeIndices() { + loadedIdx.clear(); + reverseIdx.clear(); + bitmapIdx.clear(); } /** @@ -416,185 +426,202 @@ private void copyAsIs2(PackOutputStream out, LocalObjectToPack src, final CRC32 crc2 = validate ? new CRC32() : null; final byte[] buf = out.getCopyBuffer(); + boolean isHeaderWritten = false; // Rip apart the header so we can discover the size. // - readFully(src.offset, buf, 0, 20, curs); - int c = buf[0] & 0xff; - final int typeCode = (c >> 4) & 7; - long inflatedLength = c & 15; - int shift = 4; - int headerCnt = 1; - while ((c & 0x80) != 0) { - c = buf[headerCnt++] & 0xff; - inflatedLength += ((long) (c & 0x7f)) << shift; - shift += 7; - } - - if (typeCode == Constants.OBJ_OFS_DELTA) { - do { - c = buf[headerCnt++] & 0xff; - } while ((c & 128) != 0); - if (validate) { - assert(crc1 != null && crc2 != null); - crc1.update(buf, 0, headerCnt); - crc2.update(buf, 0, headerCnt); - } - } else if (typeCode == Constants.OBJ_REF_DELTA) { - if (validate) { - assert(crc1 != null && crc2 != null); - crc1.update(buf, 0, headerCnt); - crc2.update(buf, 0, headerCnt); - } - - readFully(src.offset + headerCnt, buf, 0, 20, curs); - if (validate) { - assert(crc1 != null && crc2 != null); - crc1.update(buf, 0, 20); - crc2.update(buf, 0, 20); - } - headerCnt += 20; - } else if (validate) { - assert(crc1 != null && crc2 != null); - crc1.update(buf, 0, headerCnt); - crc2.update(buf, 0, headerCnt); - } - - final long dataOffset = src.offset + headerCnt; - final long dataLength = src.length; - final long expectedCRC; - final ByteArrayWindow quickCopy; - - // Verify the object isn't corrupt before sending. If it is, - // we report it missing instead. - // try { - quickCopy = curs.quickCopy(this, dataOffset, dataLength); + readFully(src.offset, buf, 0, 20, curs); - if (validate && idx().hasCRC32Support()) { - assert(crc1 != null); - // Index has the CRC32 code cached, validate the object. - // - expectedCRC = idx().findCRC32(src); - if (quickCopy != null) { - quickCopy.crc32(crc1, dataOffset, (int) dataLength); - } else { - long pos = dataOffset; - long cnt = dataLength; - while (cnt > 0) { - final int n = (int) Math.min(cnt, buf.length); - readFully(pos, buf, 0, n, curs); - crc1.update(buf, 0, n); - pos += n; - cnt -= n; - } - } - if (crc1.getValue() != expectedCRC) { - setCorrupt(src.offset); - throw new CorruptObjectException(MessageFormat.format( - JGitText.get().objectAtHasBadZlibStream, - Long.valueOf(src.offset), getPackFile())); - } - } else if (validate) { - // We don't have a CRC32 code in the index, so compute it - // now while inflating the raw data to get zlib to tell us - // whether or not the data is safe. - // - Inflater inf = curs.inflater(); - byte[] tmp = new byte[1024]; - if (quickCopy != null) { - quickCopy.check(inf, tmp, dataOffset, (int) dataLength); - } else { - assert(crc1 != null); - long pos = dataOffset; - long cnt = dataLength; - while (cnt > 0) { - final int n = (int) Math.min(cnt, buf.length); - readFully(pos, buf, 0, n, curs); - crc1.update(buf, 0, n); - inf.setInput(buf, 0, n); - while (inf.inflate(tmp, 0, tmp.length) > 0) - continue; - pos += n; - cnt -= n; - } - } - if (!inf.finished() || inf.getBytesRead() != dataLength) { - setCorrupt(src.offset); - throw new EOFException(MessageFormat.format( - JGitText.get().shortCompressedStreamAt, - Long.valueOf(src.offset))); - } - assert(crc1 != null); - expectedCRC = crc1.getValue(); - } else { - expectedCRC = -1; + int c = buf[0] & 0xff; + final int typeCode = (c >> 4) & 7; + long inflatedLength = c & 15; + int shift = 4; + int headerCnt = 1; + while ((c & 0x80) != 0) { + c = buf[headerCnt++] & 0xff; + inflatedLength += ((long) (c & 0x7f)) << shift; + shift += 7; } - } catch (DataFormatException dataFormat) { - setCorrupt(src.offset); - CorruptObjectException corruptObject = new CorruptObjectException( - MessageFormat.format( - JGitText.get().objectAtHasBadZlibStream, - Long.valueOf(src.offset), getPackFile()), - dataFormat); + if (typeCode == Constants.OBJ_OFS_DELTA) { + do { + c = buf[headerCnt++] & 0xff; + } while ((c & 128) != 0); + if (validate) { + assert(crc1 != null && crc2 != null); + crc1.update(buf, 0, headerCnt); + crc2.update(buf, 0, headerCnt); + } + } else if (typeCode == Constants.OBJ_REF_DELTA) { + if (validate) { + assert(crc1 != null && crc2 != null); + crc1.update(buf, 0, headerCnt); + crc2.update(buf, 0, headerCnt); + } - throw new StoredObjectRepresentationNotAvailableException( - corruptObject); + readFully(src.offset + headerCnt, buf, 0, 20, curs); + if (validate) { + assert(crc1 != null && crc2 != null); + crc1.update(buf, 0, 20); + crc2.update(buf, 0, 20); + } + headerCnt += 20; + } else if (validate) { + assert(crc1 != null && crc2 != null); + crc1.update(buf, 0, headerCnt); + crc2.update(buf, 0, headerCnt); + } - } catch (IOException ioError) { - throw new StoredObjectRepresentationNotAvailableException(ioError); - } + final long dataOffset = src.offset + headerCnt; + final long dataLength = src.length; + final long expectedCRC; + final ByteArrayWindow quickCopy; - if (quickCopy != null) { - // The entire object fits into a single byte array window slice, - // and we have it pinned. Write this out without copying. + // Verify the object isn't corrupt before sending. If it is, + // we report it missing instead. // - out.writeHeader(src, inflatedLength); - quickCopy.write(out, dataOffset, (int) dataLength); + try { + quickCopy = curs.quickCopy(this, dataOffset, dataLength); - } else if (dataLength <= buf.length) { - // Tiny optimization: Lots of objects are very small deltas or - // deflated commits that are likely to fit in the copy buffer. - // - if (!validate) { + if (validate && idx().hasCRC32Support()) { + assert(crc1 != null); + // Index has the CRC32 code cached, validate the object. + // + expectedCRC = idx().findCRC32(src); + if (quickCopy != null) { + quickCopy.crc32(crc1, dataOffset, (int) dataLength); + } else { + long pos = dataOffset; + long cnt = dataLength; + while (cnt > 0) { + final int n = (int) Math.min(cnt, buf.length); + readFully(pos, buf, 0, n, curs); + crc1.update(buf, 0, n); + pos += n; + cnt -= n; + } + } + if (crc1.getValue() != expectedCRC) { + setCorrupt(src.offset); + throw new CorruptObjectException(MessageFormat.format( + JGitText.get().objectAtHasBadZlibStream, + Long.valueOf(src.offset), getPackFile())); + } + } else if (validate) { + // We don't have a CRC32 code in the index, so compute it + // now while inflating the raw data to get zlib to tell us + // whether or not the data is safe. + // + Inflater inf = curs.inflater(); + byte[] tmp = new byte[1024]; + if (quickCopy != null) { + quickCopy.check(inf, tmp, dataOffset, (int) dataLength); + } else { + assert(crc1 != null); + long pos = dataOffset; + long cnt = dataLength; + while (cnt > 0) { + final int n = (int) Math.min(cnt, buf.length); + readFully(pos, buf, 0, n, curs); + crc1.update(buf, 0, n); + inf.setInput(buf, 0, n); + while (inf.inflate(tmp, 0, tmp.length) > 0) + continue; + pos += n; + cnt -= n; + } + } + if (!inf.finished() || inf.getBytesRead() != dataLength) { + setCorrupt(src.offset); + throw new EOFException(MessageFormat.format( + JGitText.get().shortCompressedStreamAt, + Long.valueOf(src.offset))); + } + assert(crc1 != null); + expectedCRC = crc1.getValue(); + } else { + expectedCRC = -1; + } + } catch (DataFormatException dataFormat) { + setCorrupt(src.offset); + + CorruptObjectException corruptObject = new CorruptObjectException( + MessageFormat.format( + JGitText.get().objectAtHasBadZlibStream, + Long.valueOf(src.offset), getPackFile()), + dataFormat); + + throw new StoredObjectRepresentationNotAvailableException( + corruptObject); + } + + if (quickCopy != null) { + // The entire object fits into a single byte array window slice, + // and we have it pinned. Write this out without copying. + // + out.writeHeader(src, inflatedLength); + isHeaderWritten = true; + quickCopy.write(out, dataOffset, (int) dataLength); + + } else if (dataLength <= buf.length) { + // Tiny optimization: Lots of objects are very small deltas or + // deflated commits that are likely to fit in the copy buffer. + // + if (!validate) { + long pos = dataOffset; + long cnt = dataLength; + while (cnt > 0) { + final int n = (int) Math.min(cnt, buf.length); + readFully(pos, buf, 0, n, curs); + pos += n; + cnt -= n; + } + } + out.writeHeader(src, inflatedLength); + isHeaderWritten = true; + out.write(buf, 0, (int) dataLength); + } else { + // Now we are committed to sending the object. As we spool it out, + // check its CRC32 code to make sure there wasn't corruption between + // the verification we did above, and us actually outputting it. + // long pos = dataOffset; long cnt = dataLength; while (cnt > 0) { final int n = (int) Math.min(cnt, buf.length); readFully(pos, buf, 0, n, curs); - pos += n; + if (validate) { + assert(crc2 != null); + crc2.update(buf, 0, n); + } cnt -= n; + if (!isHeaderWritten) { + if (invalid && cnt > 0) { + // Since this is not the last iteration and the packfile is invalid, + // better to assume the iterations will not all complete here while + // it is still likely recoverable. + throw new StoredObjectRepresentationNotAvailableException(invalidatingCause); + } + out.writeHeader(src, inflatedLength); + isHeaderWritten = true; + } + out.write(buf, 0, n); + pos += n; } - } - out.writeHeader(src, inflatedLength); - out.write(buf, 0, (int) dataLength); - } else { - // Now we are committed to sending the object. As we spool it out, - // check its CRC32 code to make sure there wasn't corruption between - // the verification we did above, and us actually outputting it. - // - out.writeHeader(src, inflatedLength); - long pos = dataOffset; - long cnt = dataLength; - while (cnt > 0) { - final int n = (int) Math.min(cnt, buf.length); - readFully(pos, buf, 0, n, curs); if (validate) { assert(crc2 != null); - crc2.update(buf, 0, n); - } - out.write(buf, 0, n); - pos += n; - cnt -= n; - } - if (validate) { - assert(crc2 != null); - if (crc2.getValue() != expectedCRC) { - throw new CorruptObjectException(MessageFormat.format( - JGitText.get().objectAtHasBadZlibStream, - Long.valueOf(src.offset), getPackFile())); + if (crc2.getValue() != expectedCRC) { + throw new CorruptObjectException(MessageFormat.format( + JGitText.get().objectAtHasBadZlibStream, + Long.valueOf(src.offset), getPackFile())); + } } } + } catch (IOException ioError) { + if (!isHeaderWritten) { + throw new StoredObjectRepresentationNotAvailableException(ioError); + } + throw ioError; } } @@ -621,42 +648,53 @@ private void readFully(final long position, final byte[] dstbuf, throw new EOFException(); } - private synchronized void beginCopyAsIs() + private void beginCopyAsIs() throws StoredObjectRepresentationNotAvailableException { - if (++activeCopyRawData == 1 && activeWindows == 0) { - try { - doOpen(); - } catch (IOException thisPackNotValid) { - throw new StoredObjectRepresentationNotAvailableException( - thisPackNotValid); + synchronized (activeLock) { + if (++activeCopyRawData == 1 && activeWindows == 0) { + try { + doOpen(); + } catch (IOException thisPackNotValid) { + throw new StoredObjectRepresentationNotAvailableException( + thisPackNotValid); + } } } } - private synchronized void endCopyAsIs() { - if (--activeCopyRawData == 0 && activeWindows == 0) - doClose(); - } - - synchronized boolean beginWindowCache() throws IOException { - if (++activeWindows == 1) { - if (activeCopyRawData == 0) - doOpen(); - return true; + private void endCopyAsIs() { + synchronized (activeLock) { + if (--activeCopyRawData == 0 && activeWindows == 0) { + doClose(); + } } - return false; } - synchronized boolean endWindowCache() { - final boolean r = --activeWindows == 0; - if (r && activeCopyRawData == 0) - doClose(); - return r; + boolean beginWindowCache() throws IOException { + synchronized (activeLock) { + if (++activeWindows == 1) { + if (activeCopyRawData == 0) { + doOpen(); + } + return true; + } + return false; + } + } + + boolean endWindowCache() { + synchronized (activeLock) { + boolean r = --activeWindows == 0; + if (r && activeCopyRawData == 0) { + doClose(); + } + return r; + } } private void doOpen() throws IOException { if (invalid) { - openFail(true, invalidatingCause); + openFail(invalidatingCause); throw new PackInvalidException(packFile, invalidatingCause); } try { @@ -667,39 +705,41 @@ private void doOpen() throws IOException { } } catch (InterruptedIOException e) { // don't invalidate the pack, we are interrupted from another thread - openFail(false, e); + openFail(e); throw e; } catch (FileNotFoundException fn) { - // don't invalidate the pack if opening an existing file failed - // since it may be related to a temporary lack of resources (e.g. - // max open files) - openFail(!packFile.exists(), fn); + if (!packFile.exists()) { + // Failure to open an existing file may be related to a temporary lack of resources + // (e.g. max open files) + invalid = true; + } + openFail(fn); throw fn; } catch (EOFException | AccessDeniedException | NoSuchFileException | CorruptObjectException | NoPackSignatureException | PackMismatchException | UnpackException | UnsupportedPackIndexVersionException | UnsupportedPackVersionException pe) { - // exceptions signaling permanent problems with a pack - openFail(true, pe); + invalid = true; // exceptions signaling permanent problems with a pack + openFail(pe); throw pe; } catch (IOException ioe) { - // mark this packfile as invalid when NFS stale file handle error - // occur - openFail(FileUtils.isStaleFileHandleInCausalChain(ioe), ioe); + if (FileUtils.isStaleFileHandleInCausalChain(ioe)) { + invalid = true; + } + openFail(ioe); throw ioe; } catch (RuntimeException ge) { // generic exceptions could be transient so we should not mark the // pack invalid to avoid false MissingObjectExceptions - openFail(false, ge); + openFail(ge); throw ge; } } - private void openFail(boolean invalidate, Exception cause) { + private void openFail(Exception cause) { activeWindows = 0; activeCopyRawData = 0; - invalid = invalidate; invalidatingCause = cause; doClose(); } @@ -791,7 +831,7 @@ private void onOpenPack() throws IOException { MessageFormat.format(JGitText.get().packChecksumMismatch, getPackFile(), PackExt.PACK.getExtension(), Hex.toHexString(buf), PackExt.INDEX.getExtension(), - Hex.toHexString(idx.packChecksum))); + Hex.toHexString(idx.getChecksum()))); } } @@ -1173,17 +1213,8 @@ synchronized PackBitmapIndex getBitmapIndex() throws IOException { return null; } - synchronized void refreshBitmapIndex(PackFile bitmapIndexFile) { - this.bitmapIdx = Optionally.empty(); - this.invalid = false; + void setBitmapIndexFile(PackFile bitmapIndexFile) { this.bitmapIdxFile = bitmapIndexFile; - try { - getBitmapIndex(); - } catch (IOException e) { - LOG.warn(JGitText.get().bitmapFailedToGet, bitmapIdxFile, e); - this.bitmapIdx = Optionally.empty(); - this.bitmapIdxFile = null; - } } private synchronized PackReverseIndex getReverseIdx() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java index 8221cff..f50c17e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -17,6 +17,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -24,6 +26,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -41,7 +44,8 @@ import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.TrustStat; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.util.FileUtils; @@ -71,7 +75,7 @@ class PackDirectory { private final AtomicReference<PackList> packList; - private final boolean trustFolderStat; + private final TrustStat trustPackStat; /** * Initialize a reference to an on-disk 'pack' directory. @@ -85,14 +89,7 @@ class PackDirectory { this.config = config; this.directory = directory; packList = new AtomicReference<>(NO_PACKS); - - // Whether to trust the pack folder's modification time. If set to false - // we will always scan the .git/objects/pack folder to check for new - // pack files. If set to true (default) we use the folder's size, - // modification time, and key (inode) and assume that no new pack files - // can be in this folder if these attributes have not changed. - trustFolderStat = config.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true); + trustPackStat = config.get(CoreConfig.KEY).getTrustPackStat(); } /** @@ -111,9 +108,7 @@ void create() throws IOException { void close() { PackList packs = packList.get(); if (packs != NO_PACKS && packList.compareAndSet(packs, NO_PACKS)) { - for (Pack p : packs.packs) { - p.close(); - } + Pack.close(Set.of(packs.packs)); } } @@ -314,38 +309,42 @@ private int checkRescanPackThreshold(int retries, PackMismatchException e) } private void handlePackError(IOException e, Pack p) { - String warnTmpl = null; + String warnTemplate = null; + String debugTemplate = null; int transientErrorCount = 0; - String errTmpl = JGitText.get().exceptionWhileReadingPack; + String errorTemplate = JGitText.get().exceptionWhileReadingPack; if ((e instanceof CorruptObjectException) || (e instanceof PackInvalidException)) { - warnTmpl = JGitText.get().corruptPack; - LOG.warn(MessageFormat.format(warnTmpl, + warnTemplate = JGitText.get().corruptPack; + LOG.warn(MessageFormat.format(warnTemplate, p.getPackFile().getAbsolutePath()), e); // Assume the pack is corrupted, and remove it from the list. remove(p); } else if (e instanceof FileNotFoundException) { if (p.getPackFile().exists()) { - errTmpl = JGitText.get().packInaccessible; + errorTemplate = JGitText.get().packInaccessible; transientErrorCount = p.incrementTransientErrorCount(); } else { - warnTmpl = JGitText.get().packWasDeleted; + debugTemplate = JGitText.get().packWasDeleted; remove(p); } } else if (FileUtils.isStaleFileHandleInCausalChain(e)) { - warnTmpl = JGitText.get().packHandleIsStale; + warnTemplate = JGitText.get().packHandleIsStale; remove(p); } else { transientErrorCount = p.incrementTransientErrorCount(); } - if (warnTmpl != null) { - LOG.warn(MessageFormat.format(warnTmpl, + if (warnTemplate != null) { + LOG.warn(MessageFormat.format(warnTemplate, p.getPackFile().getAbsolutePath()), e); + } else if (debugTemplate != null) { + LOG.debug(MessageFormat.format(debugTemplate, + p.getPackFile().getAbsolutePath()), e); } else { if (doLogExponentialBackoff(transientErrorCount)) { // Don't remove the pack from the list, as the error may be // transient. - LOG.error(MessageFormat.format(errTmpl, + LOG.error(MessageFormat.format(errorTemplate, p.getPackFile().getAbsolutePath(), Integer.valueOf(transientErrorCount)), e); } @@ -362,8 +361,26 @@ private boolean doLogExponentialBackoff(int n) { } boolean searchPacksAgain(PackList old) { - return (!trustFolderStat || old.snapshot.isModified(directory)) - && old != scanPacks(old); + switch (trustPackStat) { + case NEVER: + break; + case AFTER_OPEN: + try (InputStream stream = Files + .newInputStream(directory.toPath())) { + // open the pack directory to refresh attributes (on some NFS clients) + } catch (IOException e) { + // ignore + } + //$FALL-THROUGH$ + case ALWAYS: + if (!old.snapshot.isModified(directory)) { + return false; + } + break; + case INHERIT: + // only used in CoreConfig internally + } + return old != scanPacks(old); } void insert(Pack pack) { @@ -460,12 +477,9 @@ private PackList scanPacksImpl(PackList old) { && !oldPack.getFileSnapshot().isModified(packFile)) { forReuse.remove(packFile.getName()); list.add(oldPack); - try { - if(oldPack.getBitmapIndex() == null) { - oldPack.refreshBitmapIndex(packFilesByExt.get(BITMAP_INDEX)); - } - } catch (IOException e) { - LOG.warn(JGitText.get().bitmapAccessErrorForPackfile, oldPack.getPackName(), e); + PackFile bitMaps = packFilesByExt.get(BITMAP_INDEX); + if (bitMaps != null) { + oldPack.setBitmapIndexFile(bitMaps); } continue; } @@ -484,9 +498,7 @@ private PackList scanPacksImpl(PackList old) { return old; } - for (Pack p : forReuse.values()) { - p.close(); - } + Pack.close(new HashSet<>(forReuse.values())); if (list.isEmpty()) { return new PackList(snapshot, NO_PACKS.packs); @@ -545,7 +557,7 @@ private Map<String, Map<PackExt, PackFile>> getPackFilesByExtById() { for (String name : nameList) { try { PackFile pack = new PackFile(directory, name); - if (pack.getPackExt() != null) { + if (pack.getPackExt() != null && !pack.isTmpGCFile()) { Map<PackExt, PackFile> packByExt = packFilesByExtById .get(pack.getId()); if (packByExt == null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java index 19979d0..c9b05ad 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -27,6 +27,7 @@ public class PackFile extends File { private static final long serialVersionUID = 1L; private static final String PREFIX = "pack-"; //$NON-NLS-1$ + private static final String TMP_GC_PREFIX = ".tmp-"; //$NON-NLS-1$ private final String base; // PREFIX + id i.e. // pack-0123456789012345678901234567890123456789 @@ -126,6 +127,13 @@ public PackExt getPackExt() { } /** + * @return whether the file is a temporary GC file + */ + public boolean isTmpGCFile() { + return id.startsWith(TMP_GC_PREFIX); + } + + /** * Create a new similar PackFile with the given extension instead. * * @param ext
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java index c2c3775..b3e4efb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -42,8 +42,8 @@ * by ObjectId. * </p> */ -public abstract class PackIndex - implements Iterable<PackIndex.MutableEntry>, ObjectIdSet { +public interface PackIndex + extends Iterable<PackIndex.MutableEntry>, ObjectIdSet { /** * Open an existing pack <code>.idx</code> file for reading. * <p> @@ -61,7 +61,7 @@ public abstract class PackIndex * the file exists but could not be read due to security errors, * unrecognized data version, or unexpected data corruption. */ - public static PackIndex open(File idxFile) throws IOException { + static PackIndex open(File idxFile) throws IOException { try (SilentFileInputStream fd = new SilentFileInputStream( idxFile)) { return read(fd); @@ -92,7 +92,7 @@ public static PackIndex open(File idxFile) throws IOException { * @throws org.eclipse.jgit.errors.CorruptObjectException * the stream does not contain a valid pack index. */ - public static PackIndex read(InputStream fd) throws IOException, + static PackIndex read(InputStream fd) throws IOException, CorruptObjectException { final byte[] hdr = new byte[8]; IO.readFully(fd, hdr, 0, hdr.length); @@ -109,16 +109,13 @@ public static PackIndex read(InputStream fd) throws IOException, } private static boolean isTOC(byte[] h) { - final byte[] toc = PackIndexWriter.TOC; + final byte[] toc = BasePackIndexWriter.TOC; for (int i = 0; i < toc.length; i++) if (h[i] != toc[i]) return false; return true; } - /** Footer checksum applied on the bottom of the pack file. */ - protected byte[] packChecksum; - /** * Determine if an object is contained within the pack file. * @@ -126,12 +123,12 @@ private static boolean isTOC(byte[] h) { * the object to look for. Must not be null. * @return true if the object is listed in this index; false otherwise. */ - public boolean hasObject(AnyObjectId id) { + default boolean hasObject(AnyObjectId id) { return findOffset(id) != -1; } @Override - public boolean contains(AnyObjectId id) { + default boolean contains(AnyObjectId id) { return findOffset(id) != -1; } @@ -147,7 +144,7 @@ public boolean contains(AnyObjectId id) { * </p> */ @Override - public abstract Iterator<MutableEntry> iterator(); + Iterator<MutableEntry> iterator(); /** * Obtain the total number of objects described by this index. @@ -155,7 +152,7 @@ public boolean contains(AnyObjectId id) { * @return number of objects in this index, and likewise in the associated * pack that this index was generated from. */ - public abstract long getObjectCount(); + long getObjectCount(); /** * Obtain the total number of objects needing 64 bit offsets. @@ -163,7 +160,7 @@ public boolean contains(AnyObjectId id) { * @return number of objects in this index using a 64 bit offset; that is an * object positioned after the 2 GB position within the file. */ - public abstract long getOffset64Count(); + long getOffset64Count(); /** * Get ObjectId for the n-th object entry returned by {@link #iterator()}. @@ -185,7 +182,7 @@ public boolean contains(AnyObjectId id) { * is 0, the second is 1, etc. * @return the ObjectId for the corresponding entry. */ - public abstract ObjectId getObjectId(long nthPosition); + ObjectId getObjectId(long nthPosition); /** * Get ObjectId for the n-th object entry returned by {@link #iterator()}. @@ -209,7 +206,7 @@ public boolean contains(AnyObjectId id) { * negative, but still valid. * @return the ObjectId for the corresponding entry. */ - public final ObjectId getObjectId(int nthPosition) { + default ObjectId getObjectId(int nthPosition) { if (nthPosition >= 0) return getObjectId((long) nthPosition); final int u31 = nthPosition >>> 1; @@ -228,7 +225,7 @@ public final ObjectId getObjectId(int nthPosition) { * etc. Positions past 2**31-1 are negative, but still valid. * @return the offset in a pack for the corresponding entry. */ - protected abstract long getOffset(long nthPosition); + long getOffset(long nthPosition); /** * Locate the file offset position for the requested object. @@ -239,7 +236,7 @@ public final ObjectId getObjectId(int nthPosition) { * object does not exist in this index and is thus not stored in the * associated pack. */ - public abstract long findOffset(AnyObjectId objId); + long findOffset(AnyObjectId objId); /** * Locate the position of this id in the list of object-ids in the index @@ -250,7 +247,7 @@ public final ObjectId getObjectId(int nthPosition) { * of ids stored in this index; -1 if the object does not exist in * this index and is thus not stored in the associated pack. */ - public abstract int findPosition(AnyObjectId objId); + int findPosition(AnyObjectId objId); /** * Retrieve stored CRC32 checksum of the requested object raw-data @@ -264,7 +261,7 @@ public final ObjectId getObjectId(int nthPosition) { * @throws java.lang.UnsupportedOperationException * when this index doesn't support CRC32 checksum */ - public abstract long findCRC32(AnyObjectId objId) + long findCRC32(AnyObjectId objId) throws MissingObjectException, UnsupportedOperationException; /** @@ -272,7 +269,7 @@ public abstract long findCRC32(AnyObjectId objId) * * @return true if CRC32 is stored, false otherwise */ - public abstract boolean hasCRC32Support(); + boolean hasCRC32Support(); /** * Find objects matching the prefix abbreviation. @@ -288,8 +285,8 @@ public abstract long findCRC32(AnyObjectId objId) * @throws java.io.IOException * the index cannot be read. */ - public abstract void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, - int matchLimit) throws IOException; + void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, + int matchLimit) throws IOException; /** * Get pack checksum @@ -297,18 +294,18 @@ public abstract void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, * @return the checksum of the pack; caller must not modify it * @since 5.5 */ - public byte[] getChecksum() { - return packChecksum; - } + byte[] getChecksum(); /** * Represent mutable entry of pack index consisting of object id and offset * in pack (both mutable). * */ - public static class MutableEntry { + class MutableEntry { + /** Buffer of the ObjectId visited by the EntriesIterator. */ final MutableObjectId idBuffer = new MutableObjectId(); + /** Offset into the packfile of the current object. */ long offset; /** @@ -326,7 +323,6 @@ public long getOffset() { * @return hex string describing the object id of this entry. */ public String name() { - ensureId(); return idBuffer.name(); } @@ -336,7 +332,6 @@ public String name() { * @return a copy of the object id. */ public ObjectId toObjectId() { - ensureId(); return idBuffer.toObjectId(); } @@ -347,27 +342,64 @@ public ObjectId toObjectId() { */ public MutableEntry cloneEntry() { final MutableEntry r = new MutableEntry(); - ensureId(); r.idBuffer.fromObjectId(idBuffer); r.offset = offset; return r; } - void ensureId() { - // Override in implementations. + /** + * Similar to {@link Comparable#compareTo(Object)}, using only the + * object id in the entry. + * + * @param other + * Another mutable entry (probably from another index) + * + * @return a negative integer, zero, or a positive integer as this + * object is less than, equal to, or greater than the specified + * object. + */ + public int compareBySha1To(MutableEntry other) { + return idBuffer.compareTo(other.idBuffer); + } + + /** + * Copy the current ObjectId to dest + * <p> + * Like {@link #toObjectId()}, but reusing the destination instead of + * creating a new ObjectId instance. + * + * @param dest + * destination for the object id + */ + public void copyOidTo(MutableObjectId dest) { + dest.fromObjectId(idBuffer); } } + /** + * Base implementation of the iterator over index entries. + */ abstract class EntriesIterator implements Iterator<MutableEntry> { - protected final MutableEntry entry = initEntry(); + private final long objectCount; - protected long returnedNumber = 0; + private final MutableEntry entry = new MutableEntry(); - protected abstract MutableEntry initEntry(); + /** Counts number of entries accessed so far. */ + private long returnedNumber = 0; + + /** + * Construct an iterator that can move objectCount times forward. + * + * @param objectCount + * the number of objects in the PackFile. + */ + protected EntriesIterator(long objectCount) { + this.objectCount = objectCount; + } @Override public boolean hasNext() { - return returnedNumber < getObjectCount(); + return returnedNumber < objectCount; } /** @@ -375,7 +407,55 @@ public boolean hasNext() { * element. */ @Override - public abstract MutableEntry next(); + public MutableEntry next() { + readNext(); + returnedNumber++; + return entry; + } + + /** + * Used by subclasses to load the next entry into the MutableEntry. + * <p> + * Subclasses are expected to populate the entry with + * {@link #setIdBuffer} and {@link #setOffset}. + */ + protected abstract void readNext(); + + /** + * Copies to the entry an {@link ObjectId} from the int buffer and + * position idx + * + * @param raw + * the raw data + * @param idx + * the index into {@code raw} + */ + protected void setIdBuffer(int[] raw, int idx) { + entry.idBuffer.fromRaw(raw, idx); + } + + /** + * Copies to the entry an {@link ObjectId} from the byte array at + * position idx. + * + * @param raw + * the raw data + * @param idx + * the index into {@code raw} + */ + protected void setIdBuffer(byte[] raw, int idx) { + entry.idBuffer.fromRaw(raw, idx); + } + + /** + * Sets the {@code offset} to the entry + * + * @param offset + * the offset in the pack file + */ + protected void setOffset(long offset) { + entry.offset = offset; + } @Override public void remove() {
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 5180df4..be48358 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
@@ -29,13 +29,16 @@ import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.NB; -class PackIndexV1 extends PackIndex { +class PackIndexV1 implements PackIndex { private static final int IDX_HDR_LEN = 256 * 4; private static final int RECORD_SIZE = 4 + Constants.OBJECT_ID_LENGTH; private final long[] idxHeader; + /** Footer checksum applied on the bottom of the pack file. */ + protected byte[] packChecksum; + byte[][] idxdata; private long objectCnt; @@ -118,7 +121,7 @@ public ObjectId getObjectId(long nthPosition) { } @Override - protected long getOffset(long nthPosition) { + public long getOffset(long nthPosition) { final int levelOne = findLevelOne(nthPosition); final int levelTwo = getLevelTwo(nthPosition, levelOne); final int p = (4 + Constants.OBJECT_ID_LENGTH) * levelTwo; @@ -200,7 +203,7 @@ public boolean hasCRC32Support() { @Override public Iterator<MutableEntry> iterator() { - return new IndexV1Iterator(); + return new EntriesIteratorV1(this); } @Override @@ -238,32 +241,35 @@ private static int idOffset(int mid) { return (RECORD_SIZE * mid) + 4; } - private class IndexV1Iterator extends EntriesIterator { - int levelOne; + @Override + public byte[] getChecksum() { + return packChecksum; + } - int levelTwo; + private static class EntriesIteratorV1 extends EntriesIterator { + private int levelOne; - @Override - protected MutableEntry initEntry() { - return new MutableEntry() { - @Override - protected void ensureId() { - idBuffer.fromRaw(idxdata[levelOne], levelTwo - - Constants.OBJECT_ID_LENGTH); - } - }; + private int levelTwo; + + private final PackIndexV1 packIndex; + + private EntriesIteratorV1(PackIndexV1 packIndex) { + super(packIndex.objectCnt); + this.packIndex = packIndex; } @Override - public MutableEntry next() { - for (; levelOne < idxdata.length; levelOne++) { - if (idxdata[levelOne] == null) + protected void readNext() { + for (; levelOne < packIndex.idxdata.length; levelOne++) { + if (packIndex.idxdata[levelOne] == null) continue; - if (levelTwo < idxdata[levelOne].length) { - entry.offset = NB.decodeUInt32(idxdata[levelOne], levelTwo); - levelTwo += Constants.OBJECT_ID_LENGTH + 4; - returnedNumber++; - return entry; + if (levelTwo < packIndex.idxdata[levelOne].length) { + super.setOffset(NB.decodeUInt32(packIndex.idxdata[levelOne], + levelTwo)); + this.levelTwo += Constants.OBJECT_ID_LENGTH + 4; + super.setIdBuffer(packIndex.idxdata[levelOne], + levelTwo - Constants.OBJECT_ID_LENGTH); + return; } levelTwo = 0; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java index 751b62d..36e54fc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
@@ -28,7 +28,7 @@ import org.eclipse.jgit.util.NB; /** Support for the pack index v2 format. */ -class PackIndexV2 extends PackIndex { +class PackIndexV2 implements PackIndex { private static final long IS_O64 = 1L << 31; private static final int FANOUT = 256; @@ -37,6 +37,9 @@ class PackIndexV2 extends PackIndex { private static final byte[] NO_BYTES = {}; + /** Footer checksum applied on the bottom of the pack file. */ + protected byte[] packChecksum; + private long objectCnt; private final long[] fanoutTable; @@ -221,7 +224,7 @@ public boolean hasCRC32Support() { @Override public Iterator<MutableEntry> iterator() { - return new EntriesIteratorV2(); + return new EntriesIteratorV2(this); } @Override @@ -281,37 +284,39 @@ else if (cmp == 0) { return -1; } - private class EntriesIteratorV2 extends EntriesIterator { - int levelOne; + @Override + public byte[] getChecksum() { + return packChecksum; + } - int levelTwo; + private static class EntriesIteratorV2 extends EntriesIterator { + private int levelOne = 0; - @Override - protected MutableEntry initEntry() { - return new MutableEntry() { - @Override - protected void ensureId() { - idBuffer.fromRaw(names[levelOne], levelTwo - - Constants.OBJECT_ID_LENGTH / 4); - } - }; + private int levelTwo = 0; + + private final PackIndexV2 packIndex; + + private EntriesIteratorV2(PackIndexV2 packIndex) { + super(packIndex.objectCnt); + this.packIndex = packIndex; } @Override - public MutableEntry next() { - for (; levelOne < names.length; levelOne++) { - if (levelTwo < names[levelOne].length) { + protected void readNext() { + for (; levelOne < packIndex.names.length; levelOne++) { + if (levelTwo < packIndex.names[levelOne].length) { int idx = levelTwo / (Constants.OBJECT_ID_LENGTH / 4) * 4; - long offset = NB.decodeUInt32(offset32[levelOne], idx); + long offset = NB.decodeUInt32(packIndex.offset32[levelOne], + idx); if ((offset & IS_O64) != 0) { idx = (8 * (int) (offset & ~IS_O64)); - offset = NB.decodeUInt64(offset64, idx); + offset = NB.decodeUInt64(packIndex.offset64, idx); } - entry.offset = offset; - - levelTwo += Constants.OBJECT_ID_LENGTH / 4; - returnedNumber++; - return entry; + super.setOffset(offset); + this.levelTwo += Constants.OBJECT_ID_LENGTH / 4; + super.setIdBuffer(packIndex.names[levelOne], + levelTwo - Constants.OBJECT_ID_LENGTH / 4); + return; } levelTwo = 0; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java index 7e28b5e..f0b6193 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV1.java
@@ -21,10 +21,10 @@ /** * Creates the version 1 (old style) pack table of contents files. * - * @see PackIndexWriter + * @see BasePackIndexWriter * @see PackIndexV1 */ -class PackIndexWriterV1 extends PackIndexWriter { +class PackIndexWriterV1 extends BasePackIndexWriter { static boolean canStore(PackedObjectInfo oe) { // We are limited to 4 GB per pack as offset is 32 bit unsigned int. //
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java index fc5ef61..b72b35a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexWriterV2.java
@@ -19,10 +19,10 @@ /** * Creates the version 2 pack table of contents files. * - * @see PackIndexWriter + * @see BasePackIndexWriter * @see PackIndexV2 */ -class PackIndexWriterV2 extends PackIndexWriter { +class PackIndexWriterV2 extends BasePackIndexWriter { private static final int MAX_OFFSET_32 = 0x7fffffff; private static final int IS_OFFSET_64 = 0x80000000;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java index 1b092a3..55e047b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackInserter.java
@@ -77,6 +77,7 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; @@ -320,7 +321,8 @@ public void flush() throws IOException { private static void writePackIndex(File idx, byte[] packHash, List<PackedObjectInfo> list) throws IOException { try (OutputStream os = new FileOutputStream(idx)) { - PackIndexWriter w = PackIndexWriter.createVersion(os, INDEX_VERSION); + PackIndexWriter w = BasePackIndexWriter.createVersion(os, + INDEX_VERSION); w.write(list, packHash); } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackObjectSizeIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackObjectSizeIndexV1.java index a3d74be..9957f54 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackObjectSizeIndexV1.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackObjectSizeIndexV1.java
@@ -12,7 +12,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import java.util.Arrays; +import java.text.MessageFormat; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.util.NB; @@ -35,7 +35,7 @@ class PackObjectSizeIndexV1 implements PackObjectSizeIndex { private final UInt24Array positions24; - private final int[] positions32; + private final IntArray positions32; /** * Parallel array to concat(positions24, positions32) with the size of the @@ -45,35 +45,37 @@ class PackObjectSizeIndexV1 implements PackObjectSizeIndex { * doesn't fit in an int and |value|-1 is the position for the size in the * size64 array e.g. a value of -1 is sizes64[0], -2 = sizes64[1], ... */ - private final int[] sizes32; + private final IntArray sizes32; - private final long[] sizes64; + private final LongArray sizes64; static PackObjectSizeIndex parse(InputStream in) throws IOException { /** Header and version already out of the input */ - IndexInputStreamReader stream = new IndexInputStreamReader(in); - int threshold = stream.readInt(); // minSize - int objCount = stream.readInt(); + byte[] buffer = new byte[8]; + in.readNBytes(buffer, 0, 8); + int threshold = NB.decodeInt32(buffer, 0); // minSize + int objCount = NB.decodeInt32(buffer, 4); if (objCount == 0) { return new EmptyPackObjectSizeIndex(threshold); } - return new PackObjectSizeIndexV1(stream, threshold, objCount); + return new PackObjectSizeIndexV1(in, threshold, objCount); } - private PackObjectSizeIndexV1(IndexInputStreamReader stream, int threshold, + private PackObjectSizeIndexV1(InputStream stream, int threshold, int objCount) throws IOException { this.threshold = threshold; UInt24Array pos24 = null; - int[] pos32 = null; + IntArray pos32 = null; + StreamHelper helper = new StreamHelper(); byte positionEncoding; - while ((positionEncoding = stream.readByte()) != 0) { + while ((positionEncoding = helper.readByte(stream)) != 0) { if (Byte.compareUnsigned(positionEncoding, BITS_24) == 0) { - int sz = stream.readInt(); + int sz = helper.readInt(stream); pos24 = new UInt24Array(stream.readNBytes(sz * 3)); } else if (Byte.compareUnsigned(positionEncoding, BITS_32) == 0) { - int sz = stream.readInt(); - pos32 = stream.readIntArray(sz); + int sz = helper.readInt(stream); + pos32 = IntArray.from(stream, sz); } else { throw new UnsupportedEncodingException( String.format(JGitText.get().unknownPositionEncoding, @@ -81,16 +83,16 @@ private PackObjectSizeIndexV1(IndexInputStreamReader stream, int threshold, } } positions24 = pos24 != null ? pos24 : UInt24Array.EMPTY; - positions32 = pos32 != null ? pos32 : new int[0]; + positions32 = pos32 != null ? pos32 : IntArray.EMPTY; - sizes32 = stream.readIntArray(objCount); - int c64sizes = stream.readInt(); + sizes32 = IntArray.from(stream, objCount); + int c64sizes = helper.readInt(stream); if (c64sizes == 0) { - sizes64 = new long[0]; + sizes64 = LongArray.EMPTY; return; } - sizes64 = stream.readLongArray(c64sizes); - int c128sizes = stream.readInt(); + sizes64 = LongArray.from(stream, c64sizes); + int c128sizes = helper.readInt(stream); if (c128sizes != 0) { // this MUST be 0 (we don't support 128 bits sizes yet) throw new IOException(JGitText.get().unsupportedSizesObjSizeIndex); @@ -102,8 +104,8 @@ public long getSize(int idxOffset) { int pos = -1; if (!positions24.isEmpty() && idxOffset <= positions24.getLastValue()) { pos = positions24.binarySearch(idxOffset); - } else if (positions32.length > 0 && idxOffset >= positions32[0]) { - int pos32 = Arrays.binarySearch(positions32, idxOffset); + } else if (!positions32.empty() && idxOffset >= positions32.get(0)) { + int pos32 = positions32.binarySearch(idxOffset); if (pos32 >= 0) { pos = pos32 + positions24.size(); } @@ -112,17 +114,17 @@ public long getSize(int idxOffset) { return -1; } - int objSize = sizes32[pos]; + int objSize = sizes32.get(pos); if (objSize < 0) { int secondPos = Math.abs(objSize) - 1; - return sizes64[secondPos]; + return sizes64.get(secondPos); } return objSize; } @Override public long getObjectCount() { - return (long) positions24.size() + positions32.length; + return (long) positions24.size() + positions32.size(); } @Override @@ -131,19 +133,114 @@ public int getThreshold() { } /** - * Wrapper to read parsed content from the byte stream + * A byte[] that should be interpreted as an int[] */ - private static class IndexInputStreamReader { + private static class IntArray { + private static final IntArray EMPTY = new IntArray(new byte[0]); - private final byte[] buffer = new byte[8]; + private static final int INT_SIZE = 4; - private final InputStream in; + private final byte[] data; - IndexInputStreamReader(InputStream in) { - this.in = in; + private final int size; + + static IntArray from(InputStream in, int ints) throws IOException { + int expectedBytes = ints * INT_SIZE; + byte[] data = in.readNBytes(expectedBytes); + if (data.length < expectedBytes) { + throw new IOException(MessageFormat + .format(JGitText.get().unableToReadFullArray, + Integer.valueOf(ints))); + } + return new IntArray(data); } - int readInt() throws IOException { + private IntArray(byte[] data) { + this.data = data; + size = data.length / INT_SIZE; + } + + /** + * Returns position of element in array, -1 if not there + * + * @param needle + * element to look for + * @return position of the element in the array or -1 if not found + */ + int binarySearch(int needle) { + if (size == 0) { + return -1; + } + int high = size; + int low = 0; + do { + int mid = (low + high) >>> 1; + int cmp = Integer.compare(needle, get(mid)); + if (cmp < 0) + high = mid; + else if (cmp == 0) { + return mid; + } else + low = mid + 1; + } while (low < high); + return -1; + } + + int get(int position) { + if (position < 0 || position >= size) { + throw new IndexOutOfBoundsException(position); + } + return NB.decodeInt32(data, position * INT_SIZE); + } + + boolean empty() { + return size == 0; + } + + int size() { + return size; + } + } + + /** + * A byte[] that should be interpreted as an long[] + */ + private static class LongArray { + private static final LongArray EMPTY = new LongArray(new byte[0]); + + private static final int LONG_SIZE = 8; // bytes + + private final byte[] data; + + private final int size; + + static LongArray from(InputStream in, int longs) throws IOException { + byte[] data = in.readNBytes(longs * LONG_SIZE); + if (data.length < longs * LONG_SIZE) { + throw new IOException(MessageFormat + .format(JGitText.get().unableToReadFullArray, + Integer.valueOf(longs))); + } + return new LongArray(data); + } + + private LongArray(byte[] data) { + this.data = data; + size = data.length / LONG_SIZE; + } + + long get(int position) { + if (position < 0 || position >= size) { + throw new IndexOutOfBoundsException(position); + } + return NB.decodeInt64(data, position * LONG_SIZE); + } + } + + private static class StreamHelper { + private final byte[] buffer = new byte[8]; + + int readInt(InputStream in) throws IOException { int n = in.readNBytes(buffer, 0, 4); if (n < 4) { throw new IOException(JGitText.get().unableToReadFullInt); @@ -151,49 +248,13 @@ int readInt() throws IOException { return NB.decodeInt32(buffer, 0); } - int[] readIntArray(int intsCount) throws IOException { - if (intsCount == 0) { - return new int[0]; - } - - int[] dest = new int[intsCount]; - for (int i = 0; i < intsCount; i++) { - dest[i] = readInt(); - } - return dest; - } - - long readLong() throws IOException { - int n = in.readNBytes(buffer, 0, 8); - if (n < 8) { - throw new IOException(JGitText.get().unableToReadFullInt); - } - return NB.decodeInt64(buffer, 0); - } - - long[] readLongArray(int longsCount) throws IOException { - if (longsCount == 0) { - return new long[0]; - } - - long[] dest = new long[longsCount]; - for (int i = 0; i < longsCount; i++) { - dest[i] = readLong(); - } - return dest; - } - - byte readByte() throws IOException { + byte readByte(InputStream in) throws IOException { int n = in.readNBytes(buffer, 0, 1); if (n != 1) { throw new IOException(JGitText.get().cannotReadByte); } return buffer[0]; } - - byte[] readNBytes(int sz) throws IOException { - return in.readNBytes(sz); - } } private static class EmptyPackObjectSizeIndex
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java index ef9753c..720a3bc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackReverseIndex.java
@@ -75,20 +75,20 @@ long findNextOffset(long offset, long maxOffset) throws CorruptObjectException; /** - * Find the position in the primary index of the object at the given pack + * Find the position in the reverse index of the object at the given pack * offset. * * @param offset * the pack offset of the object - * @return the position in the primary index of the object + * @return the position in the reverse index of the object */ int findPosition(long offset); /** - * Find the object that is in the given position in the primary index. + * Find the object that is in the given position in the reverse index. * * @param nthPosition - * the position of the object in the primary index + * the position of the object in the reverse index * @return the object in that position */ ObjectId findObjectByPosition(int nthPosition);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java index 8e57bf9..05f1ef5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -16,6 +16,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.Constants.HEAD; import static org.eclipse.jgit.lib.Constants.LOGS; +import static org.eclipse.jgit.lib.Constants.L_LOGS; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; import static org.eclipse.jgit.lib.Constants.PACKED_REFS; import static org.eclipse.jgit.lib.Constants.R_HEADS; @@ -56,23 +57,25 @@ import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.api.PackRefsCommand; import org.eclipse.jgit.errors.InvalidObjectIdException; import org.eclipse.jgit.errors.LockFailedException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.ObjectWritingException; import org.eclipse.jgit.events.RefsChangedEvent; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.CoreConfig.TrustLooseRefStat; -import org.eclipse.jgit.lib.CoreConfig.TrustPackedRefsStat; +import org.eclipse.jgit.lib.CoreConfig; +import org.eclipse.jgit.lib.CoreConfig.TrustStat; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefComparator; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefWriter; +import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.SymbolicRef; import org.eclipse.jgit.revwalk.RevObject; @@ -124,6 +127,8 @@ public class RefDirectory extends RefDatabase { private final File gitDir; + private final File gitCommonDir; + final File refsDir; final File packedRefsFile; @@ -179,24 +184,19 @@ public class RefDirectory extends RefDatabase { private List<Integer> retrySleepMs = RETRY_SLEEP_MS; - private final boolean trustFolderStat; - - private final TrustPackedRefsStat trustPackedRefsStat; - - private final TrustLooseRefStat trustLooseRefStat; + private final CoreConfig coreConfig; RefDirectory(RefDirectory refDb) { parent = refDb.parent; gitDir = refDb.gitDir; + gitCommonDir = refDb.gitCommonDir; refsDir = refDb.refsDir; logsDir = refDb.logsDir; logsRefsDir = refDb.logsRefsDir; packedRefsFile = refDb.packedRefsFile; looseRefs.set(refDb.looseRefs.get()); packedRefs.set(refDb.packedRefs.get()); - trustFolderStat = refDb.trustFolderStat; - trustPackedRefsStat = refDb.trustPackedRefsStat; - trustLooseRefStat = refDb.trustLooseRefStat; + coreConfig = refDb.coreConfig; inProcessPackedRefsLock = refDb.inProcessPackedRefsLock; } @@ -204,24 +204,15 @@ public class RefDirectory extends RefDatabase { final FS fs = db.getFS(); parent = db; gitDir = db.getDirectory(); - refsDir = fs.resolve(gitDir, R_REFS); - logsDir = fs.resolve(gitDir, LOGS); - logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS); - packedRefsFile = fs.resolve(gitDir, PACKED_REFS); + gitCommonDir = db.getCommonDirectory(); + refsDir = fs.resolve(gitCommonDir, R_REFS); + logsDir = fs.resolve(gitCommonDir, LOGS); + logsRefsDir = fs.resolve(gitCommonDir, L_LOGS + R_REFS); + packedRefsFile = fs.resolve(gitCommonDir, PACKED_REFS); looseRefs.set(RefList.<LooseRef> emptyList()); packedRefs.set(NO_PACKED_REFS); - trustFolderStat = db.getConfig() - .getBoolean(ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true); - trustPackedRefsStat = db.getConfig() - .getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT, - TrustPackedRefsStat.UNSET); - trustLooseRefStat = db.getConfig() - .getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_TRUST_LOOSE_REF_STAT, - TrustLooseRefStat.ALWAYS); + coreConfig = db.getConfig().get(CoreConfig.KEY); inProcessPackedRefsLock = new ReentrantLock(true); } @@ -282,6 +273,33 @@ public void refresh() { clearReferences(); } + /** + * {@inheritDoc} + * + * For a RefDirectory database, by default this packs non-symbolic, loose + * tag refs into packed-refs. If {@code all} flag is set, this packs all the + * non-symbolic, loose refs. + */ + @Override + public void packRefs(ProgressMonitor pm, PackRefsCommand packRefs) + throws IOException { + String prefix = packRefs.isAll() ? R_REFS : R_TAGS; + Collection<Ref> refs = getRefsByPrefix(prefix); + List<String> refsToBePacked = new ArrayList<>(refs.size()); + pm.beginTask(JGitText.get().packRefs, refs.size()); + try { + for (Ref ref : refs) { + if (!ref.isSymbolic() && ref.getStorage().isLoose()) { + refsToBePacked.add(ref.getName()); + } + pm.update(1); + } + pack(refsToBePacked); + } finally { + pm.endTask(); + } + } + @Override public boolean isNameConflicting(String name) throws IOException { // Cannot be nested within an existing reference. @@ -422,6 +440,11 @@ public List<Ref> getAdditionalRefs() throws IOException { return ret; } + @Override + public ReflogReader getReflogReader(Ref ref) throws IOException { + return new ReflogReaderImpl(getRepository(), ref.getName()); + } + @SuppressWarnings("unchecked") private RefList<Ref> upcast(RefList<? extends Ref> loose) { return (RefList<Ref>) loose; @@ -939,7 +962,7 @@ else if (0 <= (idx = packed.find(dst.getName()))) PackedRefList getPackedRefs() throws IOException { final PackedRefList curList = packedRefs.get(); - switch (trustPackedRefsStat) { + switch (coreConfig.getTrustPackedRefsStat()) { case NEVER: break; case AFTER_OPEN: @@ -955,12 +978,8 @@ PackedRefList getPackedRefs() throws IOException { return curList; } break; - case UNSET: - if (trustFolderStat - && !curList.snapshot.isModified(packedRefsFile)) { - return curList; - } - break; + case INHERIT: + // only used in CoreConfig internally } return refreshPackedRefs(curList); @@ -1146,7 +1165,7 @@ private Ref readRef(String name, RefList<Ref> packed) throws IOException { LooseRef scanRef(LooseRef ref, String name) throws IOException { final File path = fileFor(name); - if (trustLooseRefStat.equals(TrustLooseRefStat.AFTER_OPEN)) { + if (coreConfig.getTrustLooseRefStat() == TrustStat.AFTER_OPEN) { refreshPathToLooseRef(Paths.get(name)); } @@ -1329,7 +1348,12 @@ File fileFor(String name) { name = name.substring(R_REFS.length()); return new File(refsDir, name); } - return new File(gitDir, name); + // HEAD needs to get resolved from git dir as resolving it from common dir + // would always lead back to current default branch + if (name.equals(HEAD)) { + return new File(gitDir, name); + } + return new File(gitCommonDir, name); } static int levelsIn(String name) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java index 21b5a54..f1888eb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
@@ -10,6 +10,8 @@ package org.eclipse.jgit.internal.storage.file; +import static org.eclipse.jgit.lib.Constants.HEAD; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -37,7 +39,9 @@ class ReflogReaderImpl implements ReflogReader { * {@code Ref} name */ ReflogReaderImpl(Repository db, String refname) { - logName = new File(db.getDirectory(), Constants.LOGS + '/' + refname); + File logBaseDir = refname.equals(HEAD) ? db.getDirectory() + : db.getCommonDirectory(); + logName = new File(logBaseDir, Constants.L_LOGS + refname); } /* (non-Javadoc)
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 30f8240..15c125c 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
@@ -15,8 +15,10 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; @@ -397,7 +399,11 @@ static final ByteWindow get(Pack pack, long offset) } static final void purge(Pack pack) { - cache.removeAll(pack); + purge(Collections.singleton(pack)); + } + + static final void purge(Set<Pack> packs) { + cache.queueRemoveAll(packs); } /** cleanup released and/or garbage collected windows. */ @@ -441,6 +447,29 @@ static final void purge(Pack pack) { private final boolean useStrongIndexRefs; + /** Removers are purely CPU/mem bound (no I/O), so likely should not go above # CPUs */ + private final int idealNumRemovers; + + /** Number of blocks to split the Pack removal into. + * + * Consolidation is better with more blocks since it increases + * the wait before moving to the next set by allowing more work + * to accumulate in the next set. On the flip side, the more + * blocks, the more synchronization overhead increasing each + * removers latency. + */ + private final int numRemovalBlocks; + + private final int removalBlockSize; + + private Set<Pack> packsToRemove = new HashSet<>(); + + private Set<Pack> packsBeingRemoved; + + private int numRemovers; + + private int blockBeingRemoved; + private WindowCache(WindowCacheConfig cfg) { tableSize = tableSize(cfg); final int lockCount = lockCount(cfg); @@ -479,6 +508,23 @@ else if (eb < 4) statsRecorder = mbean; publishMBean.set(cfg.getExposeStatsViaJmx()); + /* Since each worker will only process up to one full set of blocks, at least 2 + * workers are needed anytime there are queued removals to ensure that all the + * blocks will get processed. However, if workers are maxed out at only 2, then + * enough newer workers will never start in order to make it safe for older + * workers to quit early. At least 3 workers are needed to make older worker + * relief transitions possible. + */ + idealNumRemovers = Math.max(3, Runtime.getRuntime().availableProcessors()); + + int bs = 1024; + if (tableSize < 2 * bs) { + bs = tableSize / 2; + } + removalBlockSize = bs; + numRemovalBlocks = tableSize / removalBlockSize; + blockBeingRemoved = numRemovalBlocks - 1; + if (maxFiles < 1) throw new IllegalArgumentException(JGitText.get().openFilesMustBeAtLeast1); if (maxBytes < windowSize) @@ -708,22 +754,105 @@ private void removeAll() { } /** - * Clear all entries related to a single file. + * Asynchronously clear all entries related to files. * <p> - * Typically this method is invoked during {@link Pack#close()}, when we - * know the pack is never going to be useful to us again (for example, it no - * longer exists on disk). A concurrent reader loading an entry from this - * same pack may cause the pack to become stuck in the cache anyway. + * Typically this method is invoked during {@link Pack#close()}, or + * {@link Pack#close(Set)}, when we know the packs are never going to be + * useful to us again (for example, they no longer exist on disk after gc). + * A concurrent reader loading an entry from these same packs may cause a + * pack to become stuck in the cache anyway. * - * @param pack - * the file to purge all entries of. + * Work on clearing files will be split up into blocks so that removing + * can be shared by more than one thread. This potential work sharing + * can provide 2 optimizations for removals: + * <ol> + * <li> It provides an opportunity for separate removal requests to be + * consolidated into one removal pass.</li> + * <li> It can reduce removing thread latencies by sharing the removal work + * with other removing threads which otherwise might not have any work to do + * due to their removal request being consolidated. This makes the system + * more efficient and can actually reduce latencies as system load increases + * due to pack removals!</li> + * </ol> + * The optimizations above are all achieved without blockng threads to wait + * for other threads to complete (although naturally there are some + * synchronization points), and while ensuring that no threads do more work + * than if they were the only thread available to perform a removal. + * + * @param packs + * the files to purge all entries of */ - private void removeAll(Pack pack) { - for (int s = 0; s < tableSize; s++) { + private void queueRemoveAll(Set<Pack> packs) { + synchronized (this) { + packsToRemove.addAll(packs); + if (numRemovers >= idealNumRemovers) { + return; + } + numRemovers++; + } + for (int numRemoved = 0; removeNextBlock(numRemoved); numRemoved++) { + // empty + } + synchronized (this) { + if (numRemovers > 0) { + numRemovers--; + } + } + } + + /** Determine which block to remove next, if any, and do so. + * + * @param numRemoved + * the number of already processed block removals by the current thread + * @return whether more processing should be done by the current thread + */ + private boolean removeNextBlock(int numRemoved) { + Set<Pack> toRemove; + int block; + synchronized (this) { + if (packsBeingRemoved == null || blockBeingRemoved >= numRemovalBlocks - 1) { + if (packsToRemove.isEmpty()) { + return false; + } + + blockBeingRemoved = 0; + packsBeingRemoved = packsToRemove; + packsToRemove = new HashSet<>(); + } else { + blockBeingRemoved++; + } + + toRemove = packsBeingRemoved; + block = blockBeingRemoved; + } + + removeBlock(toRemove, block); + numRemoved++; + + /* Ensure threads never work on more than a full set of blocks (the equivalent + * of removing one Pack) */ + boolean isLast = numRemoved >= numRemovalBlocks; + synchronized (this) { + if (numRemovers >= idealNumRemovers) { + isLast = true; + } + } + return !isLast; + } + + /** Remove a block of entries for a Set of files + * @param packs + * the files to purge all entries of + * @param block + * the specific block to process removals for + */ + private void removeBlock(Set<Pack> packs, int block) { + int starting = block * removalBlockSize; + for (int s = starting; s < starting + removalBlockSize && s < tableSize; s++) { final Entry e1 = table.get(s); boolean hasDead = false; for (Entry e = e1; e != null; e = e.next) { - if (e.ref.getPack() == pack) { + if (packs.contains(e.ref.getPack())) { e.kill(); hasDead = true; } else if (e.dead)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java index 01f514b..11c4547 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -205,7 +205,7 @@ public void writeObjects(PackOutputStream out, List<ObjectToPack> list) * @param cnt * number of bytes to copy. This value may exceed the number of * bytes remaining in the window starting at offset - * <code>pos</code>. + * <code>position</code>. * @return number of bytes actually copied; this may be less than * <code>cnt</code> if <code>cnt</code> exceeded the number of bytes * available.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexConstants.java new file mode 100644 index 0000000..6122a9a --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexConstants.java
@@ -0,0 +1,55 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +class MultiPackIndexConstants { + static final int MIDX_SIGNATURE = 0x4d494458; /* MIDX */ + + static final byte MIDX_VERSION = 1; + + /** + * We infer the length of object IDs (OIDs) from this value: + * + * <pre> + * 1 => SHA-1 + * 2 => SHA-256 + * </pre> + */ + static final byte OID_HASH_VERSION = 1; + + static final int MULTIPACK_INDEX_FANOUT_SIZE = 4 * 256; + + /** + * First 4 bytes describe the chunk id. Value 0 is a terminating label. + * Other 8 bytes provide the byte-offset in current file for chunk to start. + */ + static final int CHUNK_LOOKUP_WIDTH = 12; + + /** "PNAM" chunk */ + static final int MIDX_CHUNKID_PACKNAMES = 0x504e414d; + + /** "OIDF" chunk */ + static final int MIDX_CHUNKID_OIDFANOUT = 0x4f494446; + + /** "OIDL" chunk */ + static final int MIDX_CHUNKID_OIDLOOKUP = 0x4f49444c; + + /** "OOFF" chunk */ + static final int MIDX_CHUNKID_OBJECTOFFSETS = 0x4f4f4646; + + /** "LOFF" chunk */ + static final int MIDX_CHUNKID_LARGEOFFSETS = 0x4c4f4646; + + /** "RIDX" chunk */ + static final int MIDX_CHUNKID_REVINDEX = 0x52494458; + + private MultiPackIndexConstants() { + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexPrettyPrinter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexPrettyPrinter.java new file mode 100644 index 0000000..795d39e --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexPrettyPrinter.java
@@ -0,0 +1,156 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.util.NB; + +/** + * Prints a multipack index file in a human-readable format. + * + * @since 7.2 + */ +@SuppressWarnings({ "boxing", "nls" }) +public class MultiPackIndexPrettyPrinter { + + /** + * Writes to out, in human-readable format, the multipack index in rawMidx + * + * @param rawMidx the bytes of a multipack index + * @param out a writer + */ + public static void prettyPrint(byte[] rawMidx, PrintWriter out) { + // Header (12 bytes) + out.println("[ 0] Magic: " + new String(rawMidx, 0, 4, UTF_8)); + out.println("[ 4] Version number: " + (int) rawMidx[4]); + out.println("[ 5] OID version: " + (int) rawMidx[5]); + int chunkCount = rawMidx[6]; + out.println("[ 6] # of chunks: " + chunkCount); + out.println("[ 7] # of bases: " + (int) rawMidx[7]); + int numberOfPacks = NB.decodeInt32(rawMidx, 8); + out.println("[ 8] # of packs: " + numberOfPacks); + + // Chunk lookup table + List<ChunkSegment> chunkSegments = new ArrayList<>(); + int current = printChunkLookup(out, rawMidx, chunkCount, chunkSegments); + + for (int i = 0; i < chunkSegments.size() - 1; i++) { + ChunkSegment segment = chunkSegments.get(i); + if (current != segment.startOffset()) { + throw new IllegalStateException(String.format( + "We are at byte %d, but segment should start at %d", + current, segment.startOffset())); + } + out.printf("Starting chunk: %s @ %d%n", segment.chunkName(), + segment.startOffset()); + switch (segment.chunkName()) { + case "OIDF" -> current = printOIDF(out, rawMidx, current); + case "OIDL" -> current = printOIDL(out, rawMidx, current, + chunkSegments.get(i + 1).startOffset); + case "OOFF" -> current = printOOFF(out, rawMidx, current, + chunkSegments.get(i + 1).startOffset); + case "PNAM" -> current = printPNAM(out, rawMidx, current, + chunkSegments.get(i + 1).startOffset); + case "RIDX" -> current = printRIDX(out, rawMidx, current, + chunkSegments.get(i + 1).startOffset); + default -> { + out.printf( + "Skipping %s (don't know how to print it yet)%n", + segment.chunkName()); + current = (int) chunkSegments.get(i + 1).startOffset(); + } + } + } + // Checksum is a SHA-1, use ObjectId to parse it + out.printf("[ %d] Checksum %s%n", current, + ObjectId.fromRaw(rawMidx, current).name()); + out.printf("Total size: " + (current + 20)); + } + + private static int printChunkLookup(PrintWriter out, byte[] rawMidx, int chunkCount, + List<ChunkSegment> chunkSegments) { + out.println("Starting chunk lookup @ 12"); + int current = 12; + for (int i = 0; i < chunkCount; i++) { + String chunkName = new String(rawMidx, current, 4, UTF_8); + long offset = NB.decodeInt64(rawMidx, current + 4); + out.printf("[ %d] |%8s|%8d|%n", current, chunkName, offset); + current += CHUNK_LOOKUP_WIDTH; + chunkSegments.add(new ChunkSegment(chunkName, offset)); + } + String chunkName = "0000"; + long offset = NB.decodeInt64(rawMidx, current + 4); + out.printf("[ %d] |%8s|%8d|%n", current, chunkName, offset); + current += CHUNK_LOOKUP_WIDTH; + chunkSegments.add(new ChunkSegment(chunkName, offset)); + return current; + } + + private static int printOIDF(PrintWriter out, byte[] rawMidx, int start) { + int current = start; + for (short i = 0; i < 256; i++) { + out.printf("[ %d] (%02X) %d%n", current, i, + NB.decodeInt32(rawMidx, current)); + current += 4; + } + return current; + } + + private static int printOIDL(PrintWriter out, byte[] rawMidx, int start, long end) { + int i = start; + while (i < end) { + out.printf("[ %d] %s%n", i, + ObjectId.fromRaw(rawMidx, i).name()); + i += 20; + } + return i; + } + + private static int printOOFF(PrintWriter out, byte[] rawMidx, int start, long end) { + int i = start; + while (i < end) { + out.printf("[ %d] %d %d%n", i, NB.decodeInt32(rawMidx, i), + NB.decodeInt32(rawMidx, i + 4)); + i += 8; + } + return i; + } + + private static int printRIDX(PrintWriter out, byte[] rawMidx, int start, long end) { + int i = start; + while (i < end) { + out.printf("[ %d] %d%n", i, NB.decodeInt32(rawMidx, i)); + i += 4; + } + return (int) end; + } + + private static int printPNAM(PrintWriter out, byte[] rawMidx, int start, long end) { + int nameStart = start; + for (int i = start; i < end; i++) { + if (rawMidx[i] == 0) { + out + .println(new String(rawMidx, nameStart, i - nameStart)); + nameStart = i + 1; + } + } + return (int) end; + } + + private record ChunkSegment(String chunkName, long startOffset) { + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java new file mode 100644 index 0000000..bddf3ac --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
@@ -0,0 +1,426 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_LARGEOFFSETS; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OBJECTOFFSETS; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDFANOUT; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_OIDLOOKUP; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_PACKNAMES; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_REVINDEX; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_SIGNATURE; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_VERSION; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MULTIPACK_INDEX_FANOUT_SIZE; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.OID_HASH_VERSION; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.io.CancellableDigestOutputStream; +import org.eclipse.jgit.internal.storage.midx.PackIndexMerger.MidxMutableEntry; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.util.NB; + +/** + * Writes a collection of indexes as a multipack index. + * <p> + * See <a href= + * "https://git-scm.com/docs/pack-format#_multi_pack_index_midx_files_have_the_following_format">multipack + * index format spec</a> + * + * @since 7.2 + */ +public class MultiPackIndexWriter { + + private static final int LIMIT_31_BITS = (1 << 31) - 1; + + private static final int MIDX_HEADER_SIZE = 12; + + /** + * Writes the inputs in the multipack index format in the outputStream. + * + * @param monitor + * progress monitor + * @param outputStream + * stream to write the multipack index file + * @param inputs + * pairs of name and index for each pack to include in the + * multipack index. + * @throws IOException + * Error writing to the stream + */ + public void write(ProgressMonitor monitor, OutputStream outputStream, + Map<String, PackIndex> inputs) throws IOException { + PackIndexMerger data = new PackIndexMerger(inputs); + + // List of chunks in the order they need to be written + List<ChunkHeader> chunkHeaders = createChunkHeaders(data); + long expectedSize = calculateExpectedSize(chunkHeaders); + try (CancellableDigestOutputStream out = new CancellableDigestOutputStream( + monitor, outputStream)) { + writeHeader(out, chunkHeaders.size(), data.getPackCount()); + writeChunkLookup(out, chunkHeaders); + + WriteContext ctx = new WriteContext(out, data); + for (ChunkHeader chunk : chunkHeaders) { + chunk.writerFn.write(ctx); + } + writeCheckSum(out); + if (expectedSize != out.length()) { + throw new IllegalStateException(String.format( + JGitText.get().multiPackIndexUnexpectedSize, + Long.valueOf(expectedSize), + Long.valueOf(out.length()))); + } + } catch (InterruptedIOException e) { + throw new IOException(JGitText.get().multiPackIndexWritingCancelled, + e); + } + } + + private static long calculateExpectedSize(List<ChunkHeader> chunks) { + int chunkLookup = (chunks.size() + 1) * CHUNK_LOOKUP_WIDTH; + long chunkContent = chunks.stream().mapToLong(c -> c.size).sum(); + return /* header */ 12 + chunkLookup + chunkContent + /* CRC */ 20; + } + + private List<ChunkHeader> createChunkHeaders(PackIndexMerger data) { + List<ChunkHeader> chunkHeaders = new ArrayList<>(); + chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_OIDFANOUT, + MULTIPACK_INDEX_FANOUT_SIZE, this::writeFanoutTable)); + chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_OIDLOOKUP, + (long) data.getUniqueObjectCount() * OBJECT_ID_LENGTH, + this::writeOidLookUp)); + chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_OBJECTOFFSETS, + 8L * data.getUniqueObjectCount(), this::writeObjectOffsets)); + if (data.needsLargeOffsetsChunk()) { + chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_LARGEOFFSETS, + 8L * data.getOffsetsOver31BitsCount(), + this::writeObjectLargeOffsets)); + } + chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_REVINDEX, + 4L * data.getUniqueObjectCount(), this::writeRidx)); + + int packNamesSize = data.getPackNames().stream() + .mapToInt(String::length).map(i -> i + 1 /* null at the end */) + .sum(); + chunkHeaders.add(new ChunkHeader(MIDX_CHUNKID_PACKNAMES, packNamesSize, + this::writePackfileNames)); + return chunkHeaders; + } + + /** + * Write the first 12 bytes of the multipack index. + * <p> + * These bytes include things like magic number, version, number of + * chunks... + * + * @param out + * output stream to write + * @param numChunks + * number of chunks this multipack index is going to have + * @param packCount + * number of packs covered by this multipack index + * @throws IOException + * error writing to the output stream + */ + private void writeHeader(CancellableDigestOutputStream out, int numChunks, + int packCount) throws IOException { + byte[] headerBuffer = new byte[MIDX_HEADER_SIZE]; + NB.encodeInt32(headerBuffer, 0, MIDX_SIGNATURE); + byte[] buff = { MIDX_VERSION, OID_HASH_VERSION, (byte) numChunks, + (byte) 0 }; + System.arraycopy(buff, 0, headerBuffer, 4, 4); + NB.encodeInt32(headerBuffer, 8, packCount); + out.write(headerBuffer, 0, headerBuffer.length); + out.flush(); + } + + /** + * Write a table of "chunkId, start-offset", with a special value "0, + * end-of-previous_chunk", to mark the end. + * + * @param out + * output stream to write + * @param chunkHeaders + * list of chunks in the order they are expected to be written + * @throws IOException + * error writing to the output stream + */ + private void writeChunkLookup(CancellableDigestOutputStream out, + List<ChunkHeader> chunkHeaders) throws IOException { + + // first chunk will start at header + this lookup block + long chunkStart = MIDX_HEADER_SIZE + + (long) (chunkHeaders.size() + 1) * CHUNK_LOOKUP_WIDTH; + byte[] chunkEntry = new byte[CHUNK_LOOKUP_WIDTH]; + for (ChunkHeader chunkHeader : chunkHeaders) { + NB.encodeInt32(chunkEntry, 0, chunkHeader.chunkId); + NB.encodeInt64(chunkEntry, 4, chunkStart); + out.write(chunkEntry); + chunkStart += chunkHeader.size; + } + // Terminating label for the block + // (chunkid 0, offset where the next block would start) + NB.encodeInt32(chunkEntry, 0, 0); + NB.encodeInt64(chunkEntry, 4, chunkStart); + out.write(chunkEntry); + } + + /** + * Write the fanout table for the object ids + * <p> + * Table with 256 entries (one byte), where the ith entry, F[i], stores the + * number of OIDs with first byte at most i. Thus, F[255] stores the total + * number of objects. + * + * @param ctx + * write context + * @throws IOException + * error writing to the output stream + */ + + private void writeFanoutTable(WriteContext ctx) throws IOException { + byte[] tmp = new byte[4]; + int[] fanout = new int[256]; + Iterator<MidxMutableEntry> iterator = ctx.data.bySha1Iterator(); + while (iterator.hasNext()) { + MidxMutableEntry e = iterator.next(); + fanout[e.getObjectId().getFirstByte() & 0xff]++; + } + for (int i = 1; i < fanout.length; i++) { + fanout[i] += fanout[i - 1]; + } + for (int n : fanout) { + NB.encodeInt32(tmp, 0, n); + ctx.out.write(tmp, 0, 4); + } + } + + /** + * Write the OID lookup chunk + * <p> + * A list of OIDs in sha1 order. + * + * @param ctx + * write context + * @throws IOException + * error writing to the output stream + */ + private void writeOidLookUp(WriteContext ctx) throws IOException { + byte[] tmp = new byte[OBJECT_ID_LENGTH]; + + Iterator<MidxMutableEntry> iterator = ctx.data.bySha1Iterator(); + while (iterator.hasNext()) { + MidxMutableEntry e = iterator.next(); + e.getObjectId().copyRawTo(tmp, 0); + ctx.out.write(tmp, 0, OBJECT_ID_LENGTH); + } + } + + /** + * Write the object offsets chunk + * <p> + * A list of offsets, parallel to the list of OIDs. If the offset is too + * large (see {@link #fitsIn31bits(long)}), this contains the position in + * the large offsets list (marked with a 1 in the most significant bit). + * + * @param ctx + * write context + * @throws IOException + * error writing to the output stream + */ + private void writeObjectOffsets(WriteContext ctx) throws IOException { + byte[] entry = new byte[8]; + Iterator<MidxMutableEntry> iterator = ctx.data.bySha1Iterator(); + while (iterator.hasNext()) { + MidxMutableEntry e = iterator.next(); + NB.encodeInt32(entry, 0, e.getPackId()); + if (!ctx.data.needsLargeOffsetsChunk() + || fitsIn31bits(e.getOffset())) { + NB.encodeInt32(entry, 4, (int) e.getOffset()); + } else { + int offloadedPosition = ctx.largeOffsets.append(e.getOffset()); + NB.encodeInt32(entry, 4, offloadedPosition | (1 << 31)); + } + ctx.out.write(entry); + } + } + + /** + * Writes the reverse index chunk + * <p> + * This stores the position of the objects in the main index, ordered first + * by pack and then by offset + * + * @param ctx + * write context + * @throws IOException + * erorr writing to the output stream + */ + private void writeRidx(WriteContext ctx) throws IOException { + Map<Integer, List<OffsetPosition>> packOffsets = new HashMap<>( + ctx.data.getPackCount()); + // TODO(ifrade): Brute force solution loading all offsets/packs in + // memory. We could also iterate reverse indexes looking up + // their position in the midx (and discarding if the pack doesn't + // match). + Iterator<MidxMutableEntry> iterator = ctx.data.bySha1Iterator(); + int midxPosition = 0; + while (iterator.hasNext()) { + MidxMutableEntry e = iterator.next(); + OffsetPosition op = new OffsetPosition(e.getOffset(), midxPosition); + midxPosition++; + packOffsets.computeIfAbsent(Integer.valueOf(e.getPackId()), + k -> new ArrayList<>()).add(op); + } + + for (int i = 0; i < ctx.data.getPackCount(); i++) { + List<OffsetPosition> offsetsForPack = packOffsets + .get(Integer.valueOf(i)); + if (offsetsForPack.isEmpty()) { + continue; + } + offsetsForPack.sort(Comparator.comparing(OffsetPosition::offset)); + byte[] ridxForPack = new byte[4 * offsetsForPack.size()]; + for (int j = 0; j < offsetsForPack.size(); j++) { + NB.encodeInt32(ridxForPack, j * 4, + offsetsForPack.get(j).position); + } + ctx.out.write(ridxForPack); + } + } + + /** + * Write the large offset chunk + * <p> + * A list of large offsets (long). The regular offset chunk will point to a + * position here. + * + * @param ctx + * writer context + * @throws IOException + * error writing to the output stream + */ + private void writeObjectLargeOffsets(WriteContext ctx) throws IOException { + ctx.out.write(ctx.largeOffsets.offsets, 0, + ctx.largeOffsets.bytePosition); + } + + /** + * Write the list of packfiles chunk + * <p> + * List of packfiles (in lexicographical order) with an \0 at the end + * + * @param ctx + * writer context + * @throws IOException + * error writing to the output stream + */ + private void writePackfileNames(WriteContext ctx) throws IOException { + for (String packName : ctx.data.getPackNames()) { + // Spec doesn't talk about encoding. + ctx.out.write(packName.getBytes(StandardCharsets.UTF_8)); + ctx.out.write(0); + } + } + + /** + * Write final checksum of the data written to the stream + * + * @param out + * output stream used to write + * @throws IOException + * error writing to the output stream + */ + private void writeCheckSum(CancellableDigestOutputStream out) + throws IOException { + out.write(out.getDigest()); + out.flush(); + } + + + private record OffsetPosition(long offset, int position) { + } + + /** + * If there is at least one offset value larger than 2^32-1, then the large + * offset chunk must exist, and offsets larger than 2^31-1 must be stored in + * it instead + * + * @param offset object offset + * + * @return true if the offset fits in 31 bits + */ + private static boolean fitsIn31bits(long offset) { + return offset <= LIMIT_31_BITS; + } + + private static class LargeOffsets { + private final byte[] offsets; + + private int bytePosition; + + LargeOffsets(int largeOffsetsCount) { + offsets = new byte[largeOffsetsCount * 8]; + bytePosition = 0; + } + + /** + * Add an offset to the large offset chunk + * + * @param largeOffset + * a large offset + * @return the position of the just inserted offset (as in number of + * offsets, NOT in bytes) + */ + int append(long largeOffset) { + int at = bytePosition; + NB.encodeInt64(offsets, at, largeOffset); + bytePosition += 8; + return at / 8; + } + } + + private record ChunkHeader(int chunkId, long size, ChunkWriter writerFn) { + } + + @FunctionalInterface + private interface ChunkWriter { + void write(WriteContext ctx) throws IOException; + } + + private static class WriteContext { + final CancellableDigestOutputStream out; + + final PackIndexMerger data; + + final LargeOffsets largeOffsets; + + WriteContext(CancellableDigestOutputStream out, PackIndexMerger data) { + this.out = out; + this.data = data; + this.largeOffsets = new LargeOffsets( + data.getOffsetsOver31BitsCount()); + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java new file mode 100644 index 0000000..89814af --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
@@ -0,0 +1,337 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.MutableObjectId; + +/** + * Collect the stats and offers an iterator over the union of n-pack indexes. + * <p> + * The multipack index is a list of (sha1, packid, offset) ordered by sha1. We + * can build it from the individual pack indexes (sha1, offset) ordered by sha1, + * with a simple merge ignoring duplicates. + * <p> + * This class encapsulates the merging logic and precalculates the stats that + * the index needs (like total count of objects). To limit memory consumption, + * it does the merge as it goes during the iteration and iterators use mutable + * entries. The stats of the combined index are calculated in an iteration at + * construction time. + */ +class PackIndexMerger { + + private static final int LIMIT_31_BITS = (1 << 31) - 1; + + private static final long LIMIT_32_BITS = (1L << 32) - 1; + + /** + * Object returned by the iterator. + * <p> + * The iterator returns (on each next()) the same instance with different + * values, to avoid allocating many short-lived objects. Callers should not + * keep a reference to that returned value. + */ + static class MidxMutableEntry { + // The object id + private final MutableObjectId oid = new MutableObjectId(); + + // Position of the pack in the ordered list of pack in this merger + private int packId; + + // Offset in its pack + private long offset; + + public AnyObjectId getObjectId() { + return oid; + } + + public int getPackId() { + return packId; + } + + public long getOffset() { + return offset; + } + + /** + * Copy values from another mutable entry + * + * @param packId + * packId + * @param other + * another mutable entry + */ + private void fill(int packId, PackIndex.MutableEntry other) { + other.copyOidTo(oid); + this.packId = packId; + this.offset = other.getOffset(); + } + } + + private final List<String> packNames; + + private final List<PackIndex> indexes; + + private final boolean needsLargeOffsetsChunk; + + private final int offsetsOver31BitsCount; + + private final int uniqueObjectCount; + + PackIndexMerger(Map<String, PackIndex> packs) { + this.packNames = packs.keySet().stream().sorted() + .collect(Collectors.toUnmodifiableList()); + + this.indexes = packNames.stream().map(packs::get) + .collect(Collectors.toUnmodifiableList()); + + // Iterate for duplicates + int objectCount = 0; + boolean hasLargeOffsets = false; + int over31bits = 0; + MutableObjectId lastSeen = new MutableObjectId(); + MultiIndexIterator it = new MultiIndexIterator(indexes); + while (it.hasNext()) { + MidxMutableEntry entry = it.next(); + if (lastSeen.equals(entry.oid)) { + continue; + } + // If there is at least one offset value larger than 2^32-1, then + // the large offset chunk must exist, and offsets larger than + // 2^31-1 must be stored in it instead + if (entry.offset > LIMIT_32_BITS) { + hasLargeOffsets = true; + } + if (entry.offset > LIMIT_31_BITS) { + over31bits++; + } + + lastSeen.fromObjectId(entry.oid); + objectCount++; + } + uniqueObjectCount = objectCount; + offsetsOver31BitsCount = over31bits; + needsLargeOffsetsChunk = hasLargeOffsets; + } + + /** + * Object count of the merged index (i.e. without duplicates) + * + * @return object count of the merged index + */ + int getUniqueObjectCount() { + return uniqueObjectCount; + } + + /** + * If any object in any of the indexes has an offset over 2^32-1 + * + * @return true if there is any object with offset > 2^32 -1 + */ + boolean needsLargeOffsetsChunk() { + return needsLargeOffsetsChunk; + } + + /** + * How many object have offsets over 2^31-1 + * <p> + * Per multipack index spec, IF there is large offset chunk, all this + * offsets should be there. + * + * @return number of objects with offsets over 2^31-1 + */ + int getOffsetsOver31BitsCount() { + return offsetsOver31BitsCount; + } + + /** + * List of pack names in alphabetical order. + * <p> + * Order matters: In case of duplicates, the multipack index prefers the + * first package with it. This is in the same order we are using to + * prioritize duplicates. + * + * @return List of pack names, in the order used by the merge. + */ + List<String> getPackNames() { + return packNames; + } + + /** + * How many packs are being merged + * + * @return count of packs merged + */ + int getPackCount() { + return packNames.size(); + } + + /** + * Iterator over the merged indexes in sha1 order without duplicates + * <p> + * The returned entry in the iterator is mutable, callers should NOT keep a + * reference to it. + * + * @return an iterator in sha1 order without duplicates. + */ + Iterator<MidxMutableEntry> bySha1Iterator() { + return new DedupMultiIndexIterator(new MultiIndexIterator(indexes), + getUniqueObjectCount()); + } + + /** + * For testing. Iterate all entries, not skipping duplicates (stable order) + * + * @return an iterator of all objects in sha1 order, including duplicates. + */ + Iterator<MidxMutableEntry> rawIterator() { + return new MultiIndexIterator(indexes); + } + + /** + * Iterator over n-indexes in ObjectId order. + * <p> + * It returns duplicates if the same object id is in different indexes. Wrap + * it with {@link DedupMultiIndexIterator (Iterator, int)} to avoid + * duplicates. + */ + private static final class MultiIndexIterator + implements Iterator<MidxMutableEntry> { + + private final List<PackIndexPeekIterator> indexIterators; + + private final MidxMutableEntry mutableEntry = new MidxMutableEntry(); + + MultiIndexIterator(List<PackIndex> indexes) { + this.indexIterators = new ArrayList<>(indexes.size()); + for (int i = 0; i < indexes.size(); i++) { + PackIndexPeekIterator it = new PackIndexPeekIterator(i, + indexes.get(i)); + // Position in the first element + if (it.next() != null) { + indexIterators.add(it); + } + } + } + + @Override + public boolean hasNext() { + return !indexIterators.isEmpty(); + } + + @Override + public MidxMutableEntry next() { + PackIndexPeekIterator winner = null; + for (int index = 0; index < indexIterators.size(); index++) { + PackIndexPeekIterator current = indexIterators.get(index); + if (winner == null + || current.peek().compareBySha1To(winner.peek()) < 0) { + winner = current; + } + } + + if (winner == null) { + throw new NoSuchElementException(); + } + + mutableEntry.fill(winner.getPackId(), winner.peek()); + if (winner.next() == null) { + indexIterators.remove(winner); + }; + return mutableEntry; + } + } + + private static class DedupMultiIndexIterator + implements Iterator<MidxMutableEntry> { + private final MultiIndexIterator src; + + private int remaining; + + private final MutableObjectId lastOid = new MutableObjectId(); + + DedupMultiIndexIterator(MultiIndexIterator src, int totalCount) { + this.src = src; + this.remaining = totalCount; + } + + @Override + public boolean hasNext() { + return remaining > 0; + } + + @Override + public MidxMutableEntry next() { + MidxMutableEntry next = src.next(); + while (next != null && lastOid.equals(next.oid)) { + next = src.next(); + } + + if (next == null) { + throw new NoSuchElementException(); + } + + lastOid.fromObjectId(next.oid); + remaining--; + return next; + } + } + + /** + * Convenience around the PackIndex iterator to read the current value + * multiple times without consuming it. + * <p> + * This is used to merge indexes in the multipack index, where we need to + * compare the current value between indexes multiple times to find the + * next. + * <p> + * We could also implement this keeping the position (int) and + * MutableEntry#getObjectId, but that would create an ObjectId per entry. + * This implementation reuses the MutableEntry and avoid instantiations. + */ + // Visible for testing + static class PackIndexPeekIterator { + private final Iterator<PackIndex.MutableEntry> it; + + private final int packId; + + PackIndex.MutableEntry current; + + PackIndexPeekIterator(int packId, PackIndex index) { + it = index.iterator(); + this.packId = packId; + } + + PackIndex.MutableEntry next() { + if (it.hasNext()) { + current = it.next(); + } else { + current = null; + } + return current; + } + + PackIndex.MutableEntry peek() { + return current; + } + + int getPackId() { + return packId; + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackIndexWriter.java new file mode 100644 index 0000000..f69e68d --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackIndexWriter.java
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.pack; + +import java.io.IOException; +import java.util.List; + +import org.eclipse.jgit.transport.PackedObjectInfo; + +/** + * Represents a function that accepts a collection of objects to write into a + * primary pack index storage format. + */ +public interface PackIndexWriter { + /** + * Write all object entries to the index stream. + * + * @param toStore + * sorted list of objects to store in the index. The caller must + * have previously sorted the list using + * {@link org.eclipse.jgit.transport.PackedObjectInfo}'s native + * {@link java.lang.Comparable} implementation. + * @param packDataChecksum + * checksum signature of the entire pack data content. This is + * traditionally the last 20 bytes of the pack file's own stream. + * @throws java.io.IOException + * an error occurred while writing to the output stream, or the + * underlying format cannot store the object data supplied. + */ + void write(List<? extends PackedObjectInfo> toStore, + byte[] packDataChecksum) throws IOException; +}
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 4350f97..f025d4e 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
@@ -58,10 +58,10 @@ import org.eclipse.jgit.errors.SearchForReuseTimeout; import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.internal.storage.file.PackIndexWriter; +import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; +import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder; import org.eclipse.jgit.internal.storage.file.PackObjectSizeIndexWriter; import org.eclipse.jgit.internal.storage.file.PackReverseIndexWriter; -import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AsyncObjectSizeQueue; import org.eclipse.jgit.lib.BatchingProgressMonitor; @@ -118,7 +118,7 @@ * {@link #preparePack(ProgressMonitor, Set, Set)}, and streaming with * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}. If the * pack is being stored as a file the matching index can be written out after - * writing the pack by {@link #writeIndex(OutputStream)}. An optional bitmap + * writing the pack by {@link #writeIndex(PackIndexWriter)}. An optional bitmap * index can be made by calling {@link #prepareBitmapIndex(ProgressMonitor)} * followed by {@link #writeBitmapIndex(PackBitmapIndexWriter)}. * </p> @@ -303,19 +303,6 @@ public PackWriter(Repository repo) { } /** - * Create a writer to load objects from the specified reader. - * <p> - * Objects for packing are specified in {@link #preparePack(Iterator)} or - * {@link #preparePack(ProgressMonitor, Set, Set)}. - * - * @param reader - * reader to read from the repository with. - */ - public PackWriter(ObjectReader reader) { - this(new PackConfig(), reader); - } - - /** * Create writer for specified repository. * <p> * Objects for packing are specified in {@link #preparePack(Iterator)} or @@ -1091,7 +1078,7 @@ public int getIndexVersion() { if (indexVersion <= 0) { for (BlockList<ObjectToPack> objs : objectsLists) indexVersion = Math.max(indexVersion, - PackIndexWriter.oldestPossibleFormat(objs)); + BasePackIndexWriter.oldestPossibleFormat(objs)); } return indexVersion; } @@ -1112,12 +1099,28 @@ public int getIndexVersion() { * the index data could not be written to the supplied stream. */ public void writeIndex(OutputStream indexStream) throws IOException { + writeIndex(BasePackIndexWriter.createVersion(indexStream, + getIndexVersion())); + } + + /** + * Create an index file to match the pack file just written. + * <p> + * Called after + * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}. + * <p> + * Writing an index is only required for local pack storage. Packs sent on + * the network do not need to create an index. + * + * @param iw + * an {@link PackIndexWriter} instance to write the index + * @throws java.io.IOException + * the index data could not be written to the supplied stream. + */ + public void writeIndex(PackIndexWriter iw) throws IOException { if (isIndexDisabled()) throw new IOException(JGitText.get().cachedPacksPreventsIndexCreation); - long writeStart = System.currentTimeMillis(); - final PackIndexWriter iw = PackIndexWriter.createVersion( - indexStream, getIndexVersion()); iw.write(sortByName(), packcsum); stats.timeWriting += System.currentTimeMillis() - writeStart; } @@ -2461,7 +2464,7 @@ private final boolean have(ObjectToPack ptr, AnyObjectId objectId) { * object graph at selected commits. Writing a bitmap index is an optional * feature that not all pack users may require. * <p> - * Called after {@link #writeIndex(OutputStream)}. + * Called after {@link #writeIndex(PackIndexWriter)}. * <p> * To reduce memory internal state is cleared during this method, rendering * the PackWriter instance useless for anything further than a call to write
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java index dabc1f0..bf87c4c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
@@ -14,6 +14,7 @@ import static org.eclipse.jgit.revwalk.RevFlag.SEEN; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -28,16 +29,16 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.revwalk.AddUnseenToBitmapFilter; import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl; +import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap; import org.eclipse.jgit.internal.storage.file.PackBitmapIndex; import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder; import org.eclipse.jgit.internal.storage.file.PackBitmapIndexRemapper; -import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ProgressMonitor; -import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; import org.eclipse.jgit.revwalk.BitmapWalker; import org.eclipse.jgit.revwalk.ObjectWalk; import org.eclipse.jgit.revwalk.RevCommit; @@ -99,10 +100,10 @@ class PackWriterBitmapPreparer { this.excessiveBranchCount = config.getBitmapExcessiveBranchCount(); this.excessiveBranchTipCount = Math.max(excessiveBranchCount, config.getBitmapExcessiveBranchTipCount()); - long now = SystemReader.getInstance().getCurrentTime(); + Instant now = SystemReader.getInstance().now(); long ageInSeconds = (long) config.getBitmapInactiveBranchAgeInDays() * DAY_IN_SECONDS; - this.inactiveBranchTimestamp = (now / 1000) - ageInSeconds; + this.inactiveBranchTimestamp = now.getEpochSecond() - ageInSeconds; } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java index d07713d..e9ff027 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockReader.java
@@ -32,6 +32,8 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Arrays; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -245,9 +247,9 @@ private String readValueString() { private PersonIdent readPersonIdent() { String name = readValueString(); String email = readValueString(); - long ms = readVarint64() * 1000; - int tz = readInt16(); - return new PersonIdent(name, email, ms, tz); + long epochSeconds = readVarint64(); + ZoneOffset tz = ZoneOffset.ofTotalSeconds(readInt16() * 60); + return new PersonIdent(name, email, Instant.ofEpochSecond(epochSeconds), tz); } void readBlock(BlockSource src, long pos, int fileBlockSize)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java index 3e75a9d..542d6e9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java
@@ -427,7 +427,35 @@ protected List<String> validate(String key, List<String> value) { return value; } - private static boolean patternMatchesHost(String pattern, String name) { + /** + * Tells whether a given {@code name} matches the given list of patterns, + * accounting for negative matches. + * + * @param patterns + * to test {@code name} against; any pattern starting with an + * exclamation mark is a negative pattern + * @param name + * to test + * @return {@code true} if the {@code name} matches at least one of the + * non-negative patterns and none of the negative patterns, + * {@code false} otherwise + * @since 7.1 + */ + public static boolean patternMatch(Iterable<String> patterns, String name) { + boolean doesMatch = false; + for (String pattern : patterns) { + if (pattern.startsWith("!")) { //$NON-NLS-1$ + if (patternMatches(pattern.substring(1), name)) { + return false; + } + } else if (!doesMatch && patternMatches(pattern, name)) { + doesMatch = true; + } + } + return doesMatch; + } + + private static boolean patternMatches(String pattern, String name) { if (pattern.indexOf('*') >= 0 || pattern.indexOf('?') >= 0) { final FileNameMatcher fn; try { @@ -680,18 +708,7 @@ public HostEntry(List<String> patterns) { } boolean matches(String hostName) { - boolean doesMatch = false; - for (String pattern : patterns) { - if (pattern.startsWith("!")) { //$NON-NLS-1$ - if (patternMatchesHost(pattern.substring(1), hostName)) { - return false; - } - } else if (!doesMatch - && patternMatchesHost(pattern, hostName)) { - doesMatch = true; - } - } - return doesMatch; + return patternMatch(patterns, hostName); } private static String toKey(String key) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/util/Optionally.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/util/Optionally.java index 3447f66..270b760 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/util/Optionally.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/util/Optionally.java
@@ -53,24 +53,24 @@ public class Hard<T> implements Optionally<T> { /** * The mutable optional object */ - protected T element; + protected Optional<T> optional; /** * @param element * the mutable optional object */ public Hard(T element) { - this.element = element; + optional = Optional.ofNullable(element); } @Override public void clear() { - element = null; + optional = Optional.empty(); } @Override public Optional<T> getOptional() { - return Optional.ofNullable(element); + return optional; } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbstractGpgSignatureVerifier.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbstractGpgSignatureVerifier.java deleted file mode 100644 index 06a89dc..0000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbstractGpgSignatureVerifier.java +++ /dev/null
@@ -1,71 +0,0 @@ -/* - * Copyright (C) 2024, Thomas Wolf <twolf@apache.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 -* https://www.eclipse.org/org/documents/edl-v10.php. -* -* SPDX-License-Identifier: BSD-3-Clause -*/ -package org.eclipse.jgit.lib; - -import java.io.IOException; -import java.util.Arrays; - -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevObject; -import org.eclipse.jgit.revwalk.RevTag; -import org.eclipse.jgit.util.RawParseUtils; - -/** - * Provides a base implementation of - * {@link GpgSignatureVerifier#verifySignature(RevObject, GpgConfig)}. - * - * @since 6.9 - */ -public abstract class AbstractGpgSignatureVerifier - implements GpgSignatureVerifier { - - @Override - public SignatureVerification verifySignature(RevObject object, - GpgConfig config) throws IOException { - if (object instanceof RevCommit) { - RevCommit commit = (RevCommit) object; - byte[] signatureData = commit.getRawGpgSignature(); - if (signatureData == null) { - return null; - } - byte[] raw = commit.getRawBuffer(); - // Now remove the GPG signature - byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' }; - int start = RawParseUtils.headerStart(header, raw, 0); - if (start < 0) { - return null; - } - int end = RawParseUtils.nextLfSkippingSplitLines(raw, start); - // start is at the beginning of the header's content - start -= header.length + 1; - // end is on the terminating LF; we need to skip that, too - if (end < raw.length) { - end++; - } - byte[] data = new byte[raw.length - (end - start)]; - System.arraycopy(raw, 0, data, 0, start); - System.arraycopy(raw, end, data, start, raw.length - end); - return verify(config, data, signatureData); - } else if (object instanceof RevTag) { - RevTag tag = (RevTag) object; - byte[] signatureData = tag.getRawGpgSignature(); - if (signatureData == null) { - return null; - } - byte[] raw = tag.getRawBuffer(); - // The signature is just tacked onto the end of the message, which - // is last in the buffer. - byte[] data = Arrays.copyOfRange(raw, 0, - raw.length - signatureData.length); - return verify(config, data, signatureData); - } - return null; - } -}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java index c58133a..f742e99 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
@@ -35,23 +35,6 @@ public abstract class AnyObjectId implements Comparable<AnyObjectId> { * @param secondObjectId * the second identifier to compare. Must not be null. * @return true if the two identifiers are the same. - * @deprecated use {@link #isEqual(AnyObjectId, AnyObjectId)} instead - */ - @Deprecated - @SuppressWarnings("AmbiguousMethodReference") - public static boolean equals(final AnyObjectId firstObjectId, - final AnyObjectId secondObjectId) { - return isEqual(firstObjectId, secondObjectId); - } - - /** - * Compare two object identifier byte sequences for equality. - * - * @param firstObjectId - * the first identifier to compare. Must not be null. - * @param secondObjectId - * the second identifier to compare. Must not be null. - * @return true if the two identifiers are the same. * @since 5.4 */ public static boolean isEqual(final AnyObjectId firstObjectId,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java index 5dfb648..0c1da83 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -13,13 +13,17 @@ import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BARE; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WORKTREE; +import static org.eclipse.jgit.lib.Constants.CONFIG; import static org.eclipse.jgit.lib.Constants.DOT_GIT; +import static org.eclipse.jgit.lib.Constants.GITDIR_FILE; import static org.eclipse.jgit.lib.Constants.GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY; import static org.eclipse.jgit.lib.Constants.GIT_CEILING_DIRECTORIES_KEY; +import static org.eclipse.jgit.lib.Constants.GIT_COMMON_DIR_KEY; import static org.eclipse.jgit.lib.Constants.GIT_DIR_KEY; import static org.eclipse.jgit.lib.Constants.GIT_INDEX_FILE_KEY; import static org.eclipse.jgit.lib.Constants.GIT_OBJECT_DIRECTORY_KEY; import static org.eclipse.jgit.lib.Constants.GIT_WORK_TREE_KEY; +import static org.eclipse.jgit.lib.Constants.OBJECTS; import java.io.File; import java.io.IOException; @@ -70,7 +74,21 @@ private static boolean isSymRef(byte[] ref) { && ref[7] == ' '; } - private static File getSymRef(File workTree, File dotGit, FS fs) + /** + * Read symbolic reference file + * + * @param workTree + * the work tree path + * @param dotGit + * the .git file + * @param fs + * th FS util + * @return the file read from symbolic reference file + * @throws java.io.IOException + * the dotGit file is invalid reference + * @since 7.0 + */ + static File getSymRef(File workTree, File dotGit, FS fs) throws IOException { byte[] content = IO.readFully(dotGit); if (!isSymRef(content)) { @@ -102,6 +120,8 @@ private static File getSymRef(File workTree, File dotGit, FS fs) private File gitDir; + private File gitCommonDir; + private File objectDirectory; private List<File> alternateObjectDirectories; @@ -172,6 +192,30 @@ public File getGitDir() { } /** + * Set common dir. + * + * @param gitCommonDir + * {@code GIT_COMMON_DIR}, the common repository meta directory. + * @return {@code this} (for chaining calls). + * @since 7.0 + */ + public B setGitCommonDir(File gitCommonDir) { + this.gitCommonDir = gitCommonDir; + this.config = null; + return self(); + } + + /** + * Get common dir. + * + * @return common dir; null if not set. + * @since 7.0 + */ + public File getGitCommonDir() { + return gitCommonDir; + } + + /** * Set the directory storing the repository's objects. * * @param objectDirectory @@ -396,9 +440,9 @@ public B setInitialBranch(String branch) throws InvalidRefNameException { * Read standard Git environment variables and configure from those. * <p> * This method tries to read the standard Git environment variables, such as - * {@code GIT_DIR} and {@code GIT_WORK_TREE} to configure this builder - * instance. If an environment variable is set, it overrides the value - * already set in this builder. + * {@code GIT_DIR}, {@code GIT_COMMON_DIR}, {@code GIT_WORK_TREE} etc. to + * configure this builder instance. If an environment variable is set, it + * overrides the value already set in this builder. * * @return {@code this} (for chaining calls). */ @@ -410,9 +454,9 @@ public B readEnvironment() { * Read standard Git environment variables and configure from those. * <p> * This method tries to read the standard Git environment variables, such as - * {@code GIT_DIR} and {@code GIT_WORK_TREE} to configure this builder - * instance. If a property is already set in the builder, the environment - * variable is not used. + * {@code GIT_DIR}, {@code GIT_COMMON_DIR}, {@code GIT_WORK_TREE} etc. to + * configure this builder instance. If a property is already set in the + * builder, the environment variable is not used. * * @param sr * the SystemReader abstraction to access the environment. @@ -425,6 +469,13 @@ public B readEnvironment(SystemReader sr) { setGitDir(new File(val)); } + if (getGitCommonDir() == null) { + String val = sr.getenv(GIT_COMMON_DIR_KEY); + if (val != null) { + setGitCommonDir(new File(val)); + } + } + if (getObjectDirectory() == null) { String val = sr.getenv(GIT_OBJECT_DIRECTORY_KEY); if (val != null) @@ -434,7 +485,7 @@ public B readEnvironment(SystemReader sr) { if (getAlternateObjectDirectories() == null) { String val = sr.getenv(GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY); if (val != null) { - for (String path : val.split(File.pathSeparator)) + for (String path : val.split(File.pathSeparator, -1)) addAlternateObjectDirectory(new File(path)); } } @@ -454,7 +505,7 @@ public B readEnvironment(SystemReader sr) { if (ceilingDirectories == null) { String val = sr.getenv(GIT_CEILING_DIRECTORIES_KEY); if (val != null) { - for (String path : val.split(File.pathSeparator)) + for (String path : val.split(File.pathSeparator, -1)) addCeilingDirectory(new File(path)); } } @@ -601,6 +652,7 @@ public B findGitDir(File current) { public B setup() throws IllegalArgumentException, IOException { requireGitDirOrWorkTree(); setupGitDir(); + setupCommonDir(); setupWorkTree(); setupInternals(); return self(); @@ -658,6 +710,20 @@ protected void setupGitDir() throws IOException { } /** + * Perform standard common dir initialization. + * + * @throws java.io.IOException + * the repository could not be accessed + * @since 7.0 + */ + protected void setupCommonDir() throws IOException { + // no gitCommonDir? Try to get it from gitDir + if (getGitCommonDir() == null) { + setGitCommonDir(safeFS().getCommonDir(getGitDir())); + } + } + + /** * Perform standard work-tree initialization. * <p> * This is a method typically invoked inside of {@link #setup()}, near the @@ -695,8 +761,12 @@ protected void setupWorkTree() throws IOException { * the repository could not be accessed */ protected void setupInternals() throws IOException { - if (getObjectDirectory() == null && getGitDir() != null) - setObjectDirectory(safeFS().resolve(getGitDir(), Constants.OBJECTS)); + if (getObjectDirectory() == null) { + File commonDir = getGitCommonDir(); + if (commonDir != null) { + setObjectDirectory(safeFS().resolve(commonDir, OBJECTS)); + } + } } /** @@ -723,12 +793,13 @@ protected Config getConfig() throws IOException { * the configuration is not available. */ protected Config loadConfig() throws IOException { - if (getGitDir() != null) { + File commonDir = getGitCommonDir(); + if (commonDir != null) { // We only want the repository's configuration file, and not // the user file, as these parameters must be unique to this // repository and not inherited from other files. // - File path = safeFS().resolve(getGitDir(), Constants.CONFIG); + File path = safeFS().resolve(commonDir, CONFIG); FileBasedConfig cfg = new FileBasedConfig(path, safeFS()); try { cfg.load(); @@ -749,8 +820,29 @@ private File guessWorkTreeOrFail() throws IOException { // String path = cfg.getString(CONFIG_CORE_SECTION, null, CONFIG_KEY_WORKTREE); - if (path != null) + if (path != null) { return safeFS().resolve(getGitDir(), path).getCanonicalFile(); + } + + /* + * We are in worktree's $GIT_DIR folder + * ".git/worktrees/<worktree-name>" and want to get the working + * tree (checkout) path; so here we have an opposite link in file + * "gitdir" showing to the ".git" file located in the working tree read + * it and convert it to absolute path if it's relative + */ + File gitDirFile = new File(getGitDir(), GITDIR_FILE); + if (gitDirFile.isFile()) { + String workDirPath = new String(IO.readFully(gitDirFile)).trim(); + File workTreeDotGitFile = new File(workDirPath); + if (!workTreeDotGitFile.isAbsolute()) { + workTreeDotGitFile = new File(getGitDir(), workDirPath) + .getCanonicalFile(); + } + if (workTreeDotGitFile != null) { + return workTreeDotGitFile.getParentFile(); + } + } // If core.bare is set, honor its value. Assume workTree is // the parent directory of the repository.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java index e15c7af..7921052 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java
@@ -187,8 +187,7 @@ public boolean isRebase() { * @since 4.5 */ public BranchRebaseMode getRebaseMode() { - return config.getEnum(BranchRebaseMode.values(), - ConfigConstants.CONFIG_BRANCH_SECTION, branchName, + return config.getEnum(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE); }
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 ea33082..ad3c2c0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -194,19 +194,6 @@ public void addParentId(AnyObjectId additionalParent) { } } - /** - * Set the encoding for the commit information. - * - * @param encodingName - * the encoding name. See - * {@link java.nio.charset.Charset#forName(String)}. - * @deprecated use {@link #setEncoding(Charset)} instead. - */ - @Deprecated - public void setEncoding(String encodingName) { - setEncoding(Charset.forName(encodingName)); - } - @Override public byte[] build() throws UnsupportedEncodingException { ByteArrayOutputStream os = new ByteArrayOutputStream();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java index f701a41..b1ba5df 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
@@ -119,7 +119,7 @@ private CommitConfig(Config rc) { if (!StringUtils.isEmptyOrNull(comment)) { if ("auto".equalsIgnoreCase(comment)) { //$NON-NLS-1$ autoCommentChar = true; - } else { + } else if (comment != null) { char first = comment.charAt(0); if (first > ' ' && first < 127) { commentCharacter = first;
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 07c5fa4..345cb22 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -34,6 +34,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.events.ConfigChangedEvent; import org.eclipse.jgit.events.ConfigChangedListener; @@ -254,9 +255,8 @@ static String escapeSubsection(String x) { * default value to return if no value was present. * @return an integer value from the configuration, or defaultValue. */ - public int getInt(final String section, final String name, - final int defaultValue) { - return typedGetter.getInt(this, section, null, name, defaultValue); + public int getInt(String section, String name, int defaultValue) { + return getInt(section, null, name, defaultValue); } /** @@ -264,6 +264,23 @@ public int getInt(final String section, final String name, * * @param section * section the key is grouped within. + * @param name + * name of the key to get. + * @return an integer value from the configuration, or {@code null} if not + * set. + * @since 7.2 + */ + @Nullable + public Integer getInt(String section, String name) { + return getInt(section, null, name); + } + + + /** + * Obtain an integer value from the configuration. + * + * @param section + * section the key is grouped within. * @param subsection * subsection name, such a remote or branch name. * @param name @@ -272,10 +289,30 @@ public int getInt(final String section, final String name, * default value to return if no value was present. * @return an integer value from the configuration, or defaultValue. */ - public int getInt(final String section, String subsection, - final String name, final int defaultValue) { + public int getInt(String section, String subsection, String name, + int defaultValue) { + Integer v = typedGetter.getInt(this, section, subsection, name, + Integer.valueOf(defaultValue)); + return v == null ? defaultValue : v.intValue(); + } + + /** + * Obtain an integer value from the configuration. + * + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @return an integer value from the configuration, or {@code null} if not + * set. + * @since 7.2 + */ + @Nullable + public Integer getInt(String section, String subsection, String name) { return typedGetter.getInt(this, section, subsection, name, - defaultValue); + null); } /** @@ -297,8 +334,30 @@ public int getInt(final String section, String subsection, */ public int getIntInRange(String section, String name, int minValue, int maxValue, int defaultValue) { - return typedGetter.getIntInRange(this, section, null, name, minValue, - maxValue, defaultValue); + return getIntInRange(section, null, name, + minValue, maxValue, defaultValue); + } + + /** + * Obtain an integer value from the configuration which must be inside given + * range. + * + * @param section + * section the key is grouped within. + * @param name + * name of the key to get. + * @param minValue + * minimum value + * @param maxValue + * maximum value + * @return an integer value from the configuration, or {@code null} if not + * set. + * @since 7.2 + */ + @Nullable + public Integer getIntInRange(String section, String name, int minValue, + int maxValue) { + return getIntInRange(section, null, name, minValue, maxValue); } /** @@ -322,8 +381,34 @@ public int getIntInRange(String section, String name, int minValue, */ public int getIntInRange(String section, String subsection, String name, int minValue, int maxValue, int defaultValue) { + Integer v = typedGetter.getIntInRange(this, section, subsection, name, + minValue, maxValue, Integer.valueOf(defaultValue)); + return v == null ? defaultValue : v.intValue(); + } + + /** + * Obtain an integer value from the configuration which must be inside given + * range. + * + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param minValue + * minimum value + * @param maxValue + * maximum value + * @return an integer value from the configuration, or {@code null} if not + * set. + * @since 7.2 + */ + @Nullable + public Integer getIntInRange(String section, String subsection, String name, + int minValue, int maxValue) { return typedGetter.getIntInRange(this, section, subsection, name, - minValue, maxValue, defaultValue); + minValue, maxValue, null); } /** @@ -338,7 +423,23 @@ public int getIntInRange(String section, String subsection, String name, * @return an integer value from the configuration, or defaultValue. */ public long getLong(String section, String name, long defaultValue) { - return typedGetter.getLong(this, section, null, name, defaultValue); + return getLong(section, null, name, defaultValue); + } + + /** + * Obtain an integer value from the configuration. + * + * @param section + * section the key is grouped within. + * @param name + * name of the key to get. + * @return an integer value from the configuration, or {@code null} if not + * set. + * @since 7.2 + */ + @Nullable + public Long getLong(String section, String name) { + return getLong(section, null, name); } /** @@ -355,9 +456,28 @@ public long getLong(String section, String name, long defaultValue) { * @return an integer value from the configuration, or defaultValue. */ public long getLong(final String section, String subsection, - final String name, final long defaultValue) { - return typedGetter.getLong(this, section, subsection, name, - defaultValue); + String name, long defaultValue) { + Long v = typedGetter.getLong(this, section, subsection, name, + Long.valueOf(defaultValue)); + return v == null ? defaultValue : v.longValue(); + } + + /** + * Obtain an integer value from the configuration. + * + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @return an integer value from the configuration, or {@code null} if not + * set. + * @since 7.2 + */ + @Nullable + public Long getLong(String section, String subsection, String name) { + return typedGetter.getLong(this, section, subsection, name, null); } /** @@ -372,9 +492,26 @@ public long getLong(final String section, String subsection, * @return true if any value or defaultValue is true, false for missing or * explicit false */ - public boolean getBoolean(final String section, final String name, - final boolean defaultValue) { - return typedGetter.getBoolean(this, section, null, name, defaultValue); + public boolean getBoolean(String section, String name, + boolean defaultValue) { + Boolean v = typedGetter.getBoolean(this, section, null, name, + Boolean.valueOf(defaultValue)); + return v == null ? defaultValue : v.booleanValue(); + } + + /** + * Get a boolean value from the git config + * + * @param section + * section the key is grouped within. + * @param name + * name of the key to get. + * @return configured boolean value, or {@code null} if not set. + * @since 7.2 + */ + @Nullable + public Boolean getBoolean(String section, String name) { + return getBoolean(section, null, name); } /** @@ -391,10 +528,28 @@ public boolean getBoolean(final String section, final String name, * @return true if any value or defaultValue is true, false for missing or * explicit false */ - public boolean getBoolean(final String section, String subsection, - final String name, final boolean defaultValue) { - return typedGetter.getBoolean(this, section, subsection, name, - defaultValue); + public boolean getBoolean(String section, String subsection, String name, + boolean defaultValue) { + Boolean v = typedGetter.getBoolean(this, section, subsection, name, + Boolean.valueOf(defaultValue)); + return v == null ? defaultValue : v.booleanValue(); + } + + /** + * Get a boolean value from the git config + * + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @return configured boolean value, or {@code null} if not set. + * @since 7.2 + */ + @Nullable + public Boolean getBoolean(String section, String subsection, String name) { + return typedGetter.getBoolean(this, section, subsection, name, null); } /** @@ -412,8 +567,8 @@ public boolean getBoolean(final String section, String subsection, * default value to return if no value was present. * @return the selected enumeration value, or {@code defaultValue}. */ - public <T extends Enum<?>> T getEnum(final String section, - final String subsection, final String name, final T defaultValue) { + public <T extends Enum<?>> T getEnum(String section, String subsection, + String name, @NonNull T defaultValue) { final T[] all = allValuesOf(defaultValue); return typedGetter.getEnum(this, all, section, subsection, name, defaultValue); @@ -448,14 +603,41 @@ public <T extends Enum<?>> T getEnum(final String section, * @param defaultValue * default value to return if no value was present. * @return the selected enumeration value, or {@code defaultValue}. + * @deprecated use {@link #getEnum(String, String, String, Enum)} or + * {{@link #getEnum(Enum[], String, String, String)}} instead. */ - public <T extends Enum<?>> T getEnum(final T[] all, final String section, - final String subsection, final String name, final T defaultValue) { + @Nullable + @Deprecated + public <T extends Enum<?>> T getEnum(T[] all, String section, + String subsection, String name, @Nullable T defaultValue) { return typedGetter.getEnum(this, all, section, subsection, name, defaultValue); } /** + * Parse an enumeration from the configuration. + * + * @param <T> + * type of the returned enum + * @param all + * all possible values in the enumeration which should be + * recognized. Typically {@code EnumType.values()}. + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @return the selected enumeration value, or {@code null} if not set. + * @since 7.2 + */ + @Nullable + public <T extends Enum<?>> T getEnum(T[] all, String section, + String subsection, String name) { + return typedGetter.getEnum(this, all, section, subsection, name, null); + } + + /** * Get string value or null if not found. * * @param section @@ -466,8 +648,8 @@ public <T extends Enum<?>> T getEnum(final T[] all, final String section, * the key name * @return a String value from the config, <code>null</code> if not found */ - public String getString(final String section, String subsection, - final String name) { + @Nullable + public String getString(String section, String subsection, String name) { return getRawString(section, subsection, name); } @@ -526,8 +708,34 @@ public String getString(final String section, String subsection, */ public long getTimeUnit(String section, String subsection, String name, long defaultValue, TimeUnit wantUnit) { + Long v = typedGetter.getTimeUnit(this, section, subsection, name, + Long.valueOf(defaultValue), wantUnit); + return v == null ? defaultValue : v.longValue(); + + } + + /** + * Parse a numerical time unit, such as "1 minute", from the configuration. + * + * @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 wantUnit + * the units of {@code defaultValue} and the return value, as + * well as the units to assume if the value does not contain an + * indication of the units. + * @return the value, or {@code null} if not set, expressed in + * {@code units}. + * @since 7.2 + */ + @Nullable + public Long getTimeUnit(String section, String subsection, String name, + TimeUnit wantUnit) { return typedGetter.getTimeUnit(this, section, subsection, name, - defaultValue, wantUnit); + null, wantUnit); } /** @@ -555,8 +763,9 @@ public long getTimeUnit(String section, String subsection, String name, * @return the {@link Path}, or {@code defaultValue} if not set * @since 5.10 */ + @Nullable public Path getPath(String section, String subsection, String name, - @NonNull FS fs, File resolveAgainst, Path defaultValue) { + @NonNull FS fs, File resolveAgainst, @Nullable Path defaultValue) { return typedGetter.getPath(this, section, subsection, name, fs, resolveAgainst, defaultValue); }
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 0edf3c5..c455032 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -78,6 +78,13 @@ public final class ConfigConstants { public static final String CONFIG_DFS_SECTION = "dfs"; /** + * The dfs cache subsection prefix. + * + * @since 7.0 + */ + public static final String CONFIG_DFS_CACHE_PREFIX = "dfs."; + + /** * The "receive" section * @since 4.6 */ @@ -199,7 +206,36 @@ public final class ConfigConstants { public static final String CONFIG_KEY_SIGNINGKEY = "signingKey"; /** + * The "ssh" subsection key. + * + * @since 7.1 + */ + public static final String CONFIG_SSH_SUBSECTION = "ssh"; + + /** + * The "defaultKeyCommand" key. + * + * @since 7.1 + */ + public static final String CONFIG_KEY_SSH_DEFAULT_KEY_COMMAND = "defaultKeyCommand"; + + /** + * The "allowedSignersFile" key. + * + * @since 7.1 + */ + public static final String CONFIG_KEY_SSH_ALLOWED_SIGNERS_FILE = "allowedSignersFile"; + + /** + * The "revocationFile" key, + * + * @since 7.1 + */ + public static final String CONFIG_KEY_SSH_REVOCATION_FILE = "revocationFile"; + + /** * The "commit" section + * * @since 5.2 */ public static final String CONFIG_COMMIT_SECTION = "commit"; @@ -332,6 +368,13 @@ public final class ConfigConstants { public static final String CONFIG_KEY_DELTA_BASE_CACHE_LIMIT = "deltaBaseCacheLimit"; /** + * The "packExtensions" key + * + * @since 7.0 + **/ + public static final String CONFIG_KEY_PACK_EXTENSIONS = "packExtensions"; + + /** * The "symlinks" key * @since 3.3 */ @@ -345,12 +388,6 @@ public final class ConfigConstants { public static final String CONFIG_KEY_STREAM_FILE_THRESHOLD = "streamFileThreshold"; /** - * @deprecated typo, use CONFIG_KEY_STREAM_FILE_THRESHOLD instead - */ - @Deprecated(since = "6.8") - public static final String CONFIG_KEY_STREAM_FILE_TRESHOLD = CONFIG_KEY_STREAM_FILE_THRESHOLD; - - /** * The "packedGitMmap" key * @since 5.1.13 */ @@ -409,6 +446,13 @@ public final class ConfigConstants { /** The "rebase" key */ public static final String CONFIG_KEY_REBASE = "rebase"; + /** + * The "checkout" key + * + * @since 7.2 + */ + public static final String CONFIG_KEY_CHECKOUT = "checkout"; + /** The "url" key */ public static final String CONFIG_KEY_URL = "url"; @@ -556,11 +600,21 @@ public final class ConfigConstants { /** * The "trustfolderstat" key in the "core" section + * * @since 3.6 + * @deprecated use {CONFIG_KEY_TRUST_STAT} instead */ + @Deprecated(since = "7.2", forRemoval = true) public static final String CONFIG_KEY_TRUSTFOLDERSTAT = "trustfolderstat"; /** + * The "trustfilestat" key in the "core"section + * + * @since 7.2 + */ + public static final String CONFIG_KEY_TRUST_STAT = "truststat"; + + /** * The "supportsAtomicFileCreation" key in the "core" section * * @since 4.5 @@ -979,6 +1033,27 @@ public final class ConfigConstants { public static final String CONFIG_KEY_TRUST_LOOSE_REF_STAT = "trustLooseRefStat"; /** + * The "trustLooseRefStat" key + * + * @since 7.2 + */ + public static final String CONFIG_KEY_TRUST_PACK_STAT = "trustPackStat"; + + /** + * The "trustLooseObjectFileStat" key + * + * @since 7.2 + */ + public static final String CONFIG_KEY_TRUST_LOOSE_OBJECT_STAT = "trustLooseObjectStat"; + + /** + * The "trustTablesListStat" key + * + * @since 7.2 + */ + public static final String CONFIG_KEY_TRUST_TABLESLIST_STAT = "trustTablesListStat"; + + /** * The "pack.preserveOldPacks" key * * @since 5.13.2 @@ -1012,4 +1087,32 @@ public final class ConfigConstants { * @since 6.7 */ public static final String CONFIG_KEY_READ_CHANGED_PATHS = "readChangedPaths"; + + /** + * The "useObjectSizeIndex" key + * + * @since 7.0 + */ + public static final String CONFIG_KEY_USE_OBJECT_SIZE_INDEX = "useObjectSizeIndex"; + + /** + * The "loadRevIndexInParallel" key + * + * @since 7.1 + */ + public static final String CONFIG_KEY_LOAD_REV_INDEX_IN_PARALLEL = "loadRevIndexInParallel"; + + /** + * The "reftable" section + * + * @since 7.2 + */ + public static final String CONFIG_REFTABLE_SECTION = "reftable"; + + /** + * The "autorefresh" key + * + * @since 7.2 + */ + public static final String CONFIG_KEY_AUTOREFRESH = "autorefresh"; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 60a23dd..997f4ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -12,10 +12,13 @@ package org.eclipse.jgit.lib; +import static java.nio.charset.StandardCharsets.US_ASCII; import static java.nio.charset.StandardCharsets.UTF_8; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; @@ -203,24 +206,6 @@ public final class Constants { */ public static final byte[] PACK_SIGNATURE = { 'P', 'A', 'C', 'K' }; - /** - * Native character encoding for commit messages, file names... - * - * @deprecated Use {@link java.nio.charset.StandardCharsets#UTF_8} directly - * instead. - */ - @Deprecated - public static final Charset CHARSET; - - /** - * Native character encoding for commit messages, file names... - * - * @deprecated Use {@link java.nio.charset.StandardCharsets#UTF_8} directly - * instead. - */ - @Deprecated - public static final String CHARACTER_ENCODING; - /** Default main branch name */ public static final String MASTER = "master"; @@ -273,6 +258,20 @@ public final class Constants { public static final String INFO_REFS = "info/refs"; /** + * Name of heads folder or file in refs. + * + * @since 7.0 + */ + public static final String HEADS = "heads"; + + /** + * Prefix for any log. + * + * @since 7.0 + */ + public static final String L_LOGS = LOGS + "/"; + + /** * Info alternates file (goes under OBJECTS) * @since 5.5 */ @@ -358,6 +357,14 @@ public final class Constants { public static final String GIT_DIR_KEY = "GIT_DIR"; /** + * The environment variable that tells us which directory is the common + * ".git" directory. + * + * @since 7.0 + */ + public static final String GIT_COMMON_DIR_KEY = "GIT_COMMON_DIR"; + + /** * The environment variable that tells us which directory is the working * directory. */ @@ -459,6 +466,36 @@ public final class Constants { public static final String GITDIR = "gitdir: "; /** + * Name of the file (inside gitDir) that references the worktree's .git + * file (opposite link). + * + * .git/worktrees/<worktree-name>/gitdir + * + * A text file containing the absolute path back to the .git file that + * points here. This file is used to verify if the linked repository has been + * manually removed in which case this directory is no longer needed. + * The modification time (mtime) of this file should be updated each time + * the linked repository is accessed. + * + * @since 7.0 + */ + public static final String GITDIR_FILE = "gitdir"; + + /** + * Name of the file (inside gitDir) that has reference to $GIT_COMMON_DIR. + * + * .git/worktrees/<worktree-name>/commondir + * + * If this file exists, $GIT_COMMON_DIR will be set to the path specified in + * this file unless it is explicitly set. If the specified path is relative, + * it is relative to $GIT_DIR. The repository with commondir is incomplete + * without the repository pointed by "commondir". + * + * @since 7.0 + */ + public static final String COMMONDIR_FILE = "commondir"; + + /** * Name of the folder (inside gitDir) where submodules are stored * * @since 3.6 @@ -494,6 +531,34 @@ public final class Constants { public static final String ATTR_BUILTIN_BINARY_MERGER = "binary"; //$NON-NLS-1$ /** + * Prefix of a GPG signature. + * + * @since 7.0 + */ + public static final String GPG_SIGNATURE_PREFIX = "-----BEGIN PGP SIGNATURE-----"; //$NON-NLS-1$ + + /** + * Prefix of a CMS signature (X.509, S/MIME). + * + * @since 7.0 + */ + public static final String CMS_SIGNATURE_PREFIX = "-----BEGIN SIGNED MESSAGE-----"; //$NON-NLS-1$ + + /** + * Prefix of an SSH signature. + * + * @since 7.0 + */ + public static final String SSH_SIGNATURE_PREFIX = "-----BEGIN SSH SIGNATURE-----"; //$NON-NLS-1$ + + /** + * Union built-in merge driver + * + * @since 6.10.1 + */ + public static final String ATTR_BUILTIN_UNION_MERGE_DRIVER = "union"; //$NON-NLS-1$ + + /** * Create a new digest function for objects. * * @return a new digest object. @@ -661,44 +726,32 @@ public static int decodeTypeString(final AnyObjectId id, * the 7-bit ASCII character space. */ public static byte[] encodeASCII(String s) { - final byte[] r = new byte[s.length()]; - for (int k = r.length - 1; k >= 0; k--) { - final char c = s.charAt(k); - if (c > 127) - throw new IllegalArgumentException(MessageFormat.format(JGitText.get().notASCIIString, s)); - r[k] = (byte) c; + try { + CharsetEncoder encoder = US_ASCII.newEncoder() + .onUnmappableCharacter(CodingErrorAction.REPORT) + .onMalformedInput(CodingErrorAction.REPORT); + return encoder.encode(CharBuffer.wrap(s)).array(); + } catch (CharacterCodingException e) { + throw new IllegalArgumentException( + MessageFormat.format(JGitText.get().notASCIIString, s), e); } - return r; } /** - * Convert a string to a byte array in the standard character encoding. + * Convert a string to a byte array in the standard character encoding UTF8. * * @param str * the string to convert. May contain any Unicode characters. * @return a byte array representing the requested string, encoded using the * default character encoding (UTF-8). - * @see #CHARACTER_ENCODING */ public static byte[] encode(String str) { - final ByteBuffer bb = UTF_8.encode(str); - final int len = bb.limit(); - if (bb.hasArray() && bb.arrayOffset() == 0) { - final byte[] arr = bb.array(); - if (arr.length == len) - return arr; - } - - final byte[] arr = new byte[len]; - bb.get(arr); - return arr; + return str.getBytes(UTF_8); } static { if (OBJECT_ID_LENGTH != newMessageDigest().getDigestLength()) throw new LinkageError(JGitText.get().incorrectOBJECT_ID_LENGTH); - CHARSET = UTF_8; - CHARACTER_ENCODING = UTF_8.name(); } /** name of the file containing the commit msg for a merge commit */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java index 9fa5d75..0e27b27 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java
@@ -17,12 +17,16 @@ import static java.util.zip.Deflater.DEFAULT_COMPRESSION; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Config.SectionParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class keeps git repository core parameters. */ public class CoreConfig { + private static final Logger LOG = LoggerFactory.getLogger(CoreConfig.class); /** Key for {@link Config#get(SectionParser)}. */ public static final Config.SectionParser<CoreConfig> KEY = CoreConfig::new; @@ -127,7 +131,9 @@ public enum LogRefUpdates { * Permissible values for {@code core.trustPackedRefsStat}. * * @since 6.1.1 + * @deprecated use {@link TrustStat} instead */ + @Deprecated(since = "7.2", forRemoval = true) public enum TrustPackedRefsStat { /** Do not trust file attributes of the packed-refs file. */ NEVER, @@ -135,12 +141,15 @@ public enum TrustPackedRefsStat { /** Trust file attributes of the packed-refs file. */ ALWAYS, - /** Open and close the packed-refs file to refresh its file attributes - * and then trust it. */ + /** + * Open and close the packed-refs file to refresh its file attributes + * and then trust it. + */ AFTER_OPEN, - /** {@code core.trustPackedRefsStat} defaults to this when it is - * not set */ + /** + * {@code core.trustPackedRefsStat} defaults to this when it is not set + */ UNSET } @@ -148,29 +157,66 @@ public enum TrustPackedRefsStat { * Permissible values for {@code core.trustLooseRefStat}. * * @since 6.9 + * @deprecated use {@link TrustStat} instead */ + @Deprecated(since = "7.2", forRemoval = true) public enum TrustLooseRefStat { /** Trust file attributes of the loose ref. */ ALWAYS, - /** Open and close parent directories of the loose ref file until the - * repository root to refresh its file attributes and then trust it. */ + /** + * Open and close parent directories of the loose ref file until the + * repository root to refresh its file attributes and then trust it. + */ AFTER_OPEN, } + /** + * Values for {@code core.trustXXX} options. + * + * @since 7.2 + */ + public enum TrustStat { + /** Do not trust file attributes of a File. */ + NEVER, + + /** Always trust file attributes of a File. */ + ALWAYS, + + /** Open and close the File to refresh its file attributes + * and then trust it. */ + AFTER_OPEN, + + /** + * Used for specific options to inherit value from value set for + * core.trustStat. + */ + INHERIT + } + private final int compression; private final int packIndexVersion; - private final LogRefUpdates logAllRefUpdates; - private final String excludesfile; private final String attributesfile; private final boolean commitGraph; + private final TrustStat trustStat; + + private final TrustStat trustPackedRefsStat; + + private final TrustStat trustLooseRefStat; + + private final TrustStat trustPackStat; + + private final TrustStat trustLooseObjectStat; + + private final TrustStat trustTablesListStat; + /** * Options for symlink handling * @@ -200,14 +246,17 @@ public enum HideDotFiles { DOTGITONLY } - private CoreConfig(Config rc) { + /** + * Create a new core configuration from the passed configuration. + * + * @param rc + * git configuration + */ + CoreConfig(Config rc) { compression = rc.getInt(ConfigConstants.CONFIG_CORE_SECTION, ConfigConstants.CONFIG_KEY_COMPRESSION, DEFAULT_COMPRESSION); packIndexVersion = rc.getInt(ConfigConstants.CONFIG_PACK_SECTION, ConfigConstants.CONFIG_KEY_INDEXVERSION, 2); - logAllRefUpdates = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, - LogRefUpdates.TRUE); excludesfile = rc.getString(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_EXCLUDESFILE); attributesfile = rc.getString(ConfigConstants.CONFIG_CORE_SECTION, @@ -215,6 +264,68 @@ private CoreConfig(Config rc) { commitGraph = rc.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, ConfigConstants.CONFIG_COMMIT_GRAPH, DEFAULT_COMMIT_GRAPH_ENABLE); + + trustStat = parseTrustStat(rc); + trustPackedRefsStat = parseTrustPackedRefsStat(rc); + trustLooseRefStat = parseTrustLooseRefStat(rc); + trustPackStat = parseTrustPackFileStat(rc); + trustLooseObjectStat = parseTrustLooseObjectFileStat(rc); + trustTablesListStat = parseTablesListStat(rc); + } + + private static TrustStat parseTrustStat(Config rc) { + Boolean tfs = rc.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, + ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT); + TrustStat ts = rc.getEnum(TrustStat.values(), + ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_TRUST_STAT); + if (tfs != null) { + if (ts == null) { + LOG.warn(JGitText.get().deprecatedTrustFolderStat); + return tfs.booleanValue() ? TrustStat.ALWAYS : TrustStat.NEVER; + } + LOG.warn(JGitText.get().precedenceTrustConfig); + } + if (ts == null) { + ts = TrustStat.ALWAYS; + } else if (ts == TrustStat.INHERIT) { + LOG.warn(JGitText.get().invalidTrustStat); + ts = TrustStat.ALWAYS; + } + return ts; + } + + private TrustStat parseTrustPackedRefsStat(Config rc) { + return inheritParseTrustStat(rc, + ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT); + } + + private TrustStat parseTrustLooseRefStat(Config rc) { + return inheritParseTrustStat(rc, + ConfigConstants.CONFIG_KEY_TRUST_LOOSE_REF_STAT); + } + + private TrustStat parseTrustPackFileStat(Config rc) { + return inheritParseTrustStat(rc, + ConfigConstants.CONFIG_KEY_TRUST_PACK_STAT); + } + + private TrustStat parseTrustLooseObjectFileStat(Config rc) { + return inheritParseTrustStat(rc, + ConfigConstants.CONFIG_KEY_TRUST_LOOSE_OBJECT_STAT); + } + + private TrustStat inheritParseTrustStat(Config rc, String key) { + TrustStat t = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, key, + TrustStat.INHERIT); + return t == TrustStat.INHERIT ? trustStat : t; + } + + private TrustStat parseTablesListStat(Config rc) { + TrustStat t = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_TRUST_TABLESLIST_STAT, + TrustStat.INHERIT); + return t == TrustStat.INHERIT ? trustStat : t; } /** @@ -236,20 +347,6 @@ public int getPackIndexVersion() { } /** - * Whether to log all refUpdates - * - * @return whether to log all refUpdates - * @deprecated since 5.6; default value depends on whether the repository is - * bare. Use - * {@link Config#getEnum(String, String, String, Enum)} - * directly. - */ - @Deprecated - public boolean isLogAllRefUpdates() { - return !LogRefUpdates.FALSE.equals(logAllRefUpdates); - } - - /** * Get path of excludesfile * * @return path of excludesfile @@ -279,4 +376,70 @@ public String getAttributesFile() { public boolean enableCommitGraph() { return commitGraph; } + + /** + * Get how far we can trust file attributes of packed-refs file which is + * used to store {@link org.eclipse.jgit.lib.Ref}s in + * {@link org.eclipse.jgit.internal.storage.file.RefDirectory}. + * + * @return how far we can trust file attributes of packed-refs file. + * + * @since 7.2 + */ + public TrustStat getTrustPackedRefsStat() { + return trustPackedRefsStat; + } + + /** + * Get how far we can trust file attributes of loose ref files which are + * used to store {@link org.eclipse.jgit.lib.Ref}s in + * {@link org.eclipse.jgit.internal.storage.file.RefDirectory}. + * + * @return how far we can trust file attributes of loose ref files. + * + * @since 7.2 + */ + public TrustStat getTrustLooseRefStat() { + return trustLooseRefStat; + } + + /** + * Get how far we can trust file attributes of packed-refs file which is + * used to store {@link org.eclipse.jgit.lib.Ref}s in + * {@link org.eclipse.jgit.internal.storage.file.RefDirectory}. + * + * @return how far we can trust file attributes of packed-refs file. + * + * @since 7.2 + */ + public TrustStat getTrustPackStat() { + return trustPackStat; + } + + /** + * Get how far we can trust file attributes of loose ref files which are + * used to store {@link org.eclipse.jgit.lib.Ref}s in + * {@link org.eclipse.jgit.internal.storage.file.RefDirectory}. + * + * @return how far we can trust file attributes of loose ref files. + * + * @since 7.2 + */ + public TrustStat getTrustLooseObjectStat() { + return trustLooseObjectStat; + } + + /** + * Get how far we can trust file attributes of the "tables.list" file which + * is used to store the list of filenames of the files storing + * {@link org.eclipse.jgit.internal.storage.reftable.Reftable}s in + * {@link org.eclipse.jgit.internal.storage.file.FileReftableDatabase}. + * + * @return how far we can trust file attributes of the "tables.list" file. + * + * @since 7.2 + */ + public TrustStat getTrustTablesListStat() { + return trustTablesListStat; + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java index a71549c..3059f28 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java
@@ -18,6 +18,7 @@ import java.util.regex.Pattern; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Config.ConfigEnum; import org.eclipse.jgit.transport.RefSpec; @@ -31,27 +32,37 @@ */ public class DefaultTypedConfigGetter implements TypedConfigGetter { + @SuppressWarnings("boxed") @Override public boolean getBoolean(Config config, String section, String subsection, String name, boolean defaultValue) { + return neverNull(getBoolean(config, section, subsection, name, + Boolean.valueOf(defaultValue))); + } + + @Nullable + @Override + public Boolean getBoolean(Config config, String section, String subsection, + String name, @Nullable Boolean defaultValue) { String n = config.getString(section, subsection, name); if (n == null) { return defaultValue; } if (Config.isMissing(n)) { - return true; + return Boolean.TRUE; } try { - return StringUtils.toBoolean(n); + return Boolean.valueOf(StringUtils.toBoolean(n)); } catch (IllegalArgumentException err) { throw new IllegalArgumentException(MessageFormat.format( JGitText.get().invalidBooleanValue, section, name, n), err); } } + @Nullable @Override public <T extends Enum<?>> T getEnum(Config config, T[] all, String section, - String subsection, String name, T defaultValue) { + String subsection, String name, @Nullable T defaultValue) { String value = config.getString(section, subsection, name); if (value == null) { return defaultValue; @@ -107,9 +118,27 @@ public <T extends Enum<?>> T getEnum(Config config, T[] all, String section, @Override public int getInt(Config config, String section, String subsection, String name, int defaultValue) { - long val = config.getLong(section, subsection, name, defaultValue); + return neverNull(getInt(config, section, subsection, name, + Integer.valueOf(defaultValue))); + } + + @Nullable + @Override + @SuppressWarnings("boxing") + public Integer getInt(Config config, String section, String subsection, + String name, @Nullable Integer defaultValue) { + Long longDefault = defaultValue != null + ? Long.valueOf(defaultValue.longValue()) + : null; + Long val = config.getLong(section, subsection, name); + if (val == null) { + val = longDefault; + } + if (val == null) { + return null; + } if (Integer.MIN_VALUE <= val && val <= Integer.MAX_VALUE) { - return (int) val; + return Integer.valueOf(Math.toIntExact(val)); } throw new IllegalArgumentException(MessageFormat .format(JGitText.get().integerValueOutOfRange, section, name)); @@ -118,37 +147,56 @@ public int getInt(Config config, String section, String subsection, @Override public int getIntInRange(Config config, String section, String subsection, String name, int minValue, int maxValue, int defaultValue) { - int val = getInt(config, section, subsection, name, defaultValue); + return neverNull(getIntInRange(config, section, subsection, name, + minValue, maxValue, Integer.valueOf(defaultValue))); + } + + @Override + @SuppressWarnings("boxing") + public Integer getIntInRange(Config config, String section, + String subsection, String name, int minValue, int maxValue, + Integer defaultValue) { + Integer val = getInt(config, section, subsection, name, defaultValue); + if (val == null) { + return null; + } if ((val >= minValue && val <= maxValue) || val == UNSET_INT) { return val; } if (subsection == null) { - throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().integerValueNotInRange, section, name, - Integer.valueOf(val), Integer.valueOf(minValue), - Integer.valueOf(maxValue))); + throw new IllegalArgumentException( + MessageFormat.format(JGitText.get().integerValueNotInRange, + section, name, val, minValue, maxValue)); } throw new IllegalArgumentException(MessageFormat.format( JGitText.get().integerValueNotInRangeSubSection, section, - subsection, name, Integer.valueOf(val), - Integer.valueOf(minValue), Integer.valueOf(maxValue))); + subsection, name, val, minValue, maxValue)); } @Override public long getLong(Config config, String section, String subsection, String name, long defaultValue) { - final String str = config.getString(section, subsection, name); + return neverNull(getLong(config, section, subsection, name, + Long.valueOf(defaultValue))); + } + + @Nullable + @Override + public Long getLong(Config config, String section, String subsection, + String name, @Nullable Long defaultValue) { + String str = config.getString(section, subsection, name); if (str == null) { return defaultValue; } try { - return StringUtils.parseLongWithSuffix(str, false); + return Long.valueOf(StringUtils.parseLongWithSuffix(str, false)); } catch (StringIndexOutOfBoundsException e) { // Empty return defaultValue; } catch (NumberFormatException nfe) { - throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().invalidIntegerValue, section, name, str), + throw new IllegalArgumentException( + MessageFormat.format(JGitText.get().invalidIntegerValue, + section, name, str), nfe); } } @@ -156,6 +204,13 @@ public long getLong(Config config, String section, String subsection, @Override public long getTimeUnit(Config config, String section, String subsection, String name, long defaultValue, TimeUnit wantUnit) { + return neverNull(getTimeUnit(config, section, subsection, name, + Long.valueOf(defaultValue), wantUnit)); + } + + @Override + public Long getTimeUnit(Config config, String section, String subsection, + String name, @Nullable Long defaultValue, TimeUnit wantUnit) { String valueString = config.getString(section, subsection, name); if (valueString == null) { @@ -232,8 +287,8 @@ public long getTimeUnit(Config config, String section, String subsection, } try { - return wantUnit.convert(Long.parseLong(digits) * inputMul, - inputUnit); + return Long.valueOf(wantUnit + .convert(Long.parseLong(digits) * inputMul, inputUnit)); } catch (NumberFormatException nfe) { IllegalArgumentException iae = notTimeUnit(section, subsection, unitName, valueString); @@ -274,4 +329,14 @@ public List<RefSpec> getRefSpecs(Config config, String section, } return result; } + + // Trick for the checkers. When we use this, one is never null, but + // they don't know. + @NonNull + private static <T> T neverNull(T one) { + if (one == null) { + throw new IllegalArgumentException(); + } + return one; + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java index 427a235..23d16db 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
@@ -24,7 +24,13 @@ public enum GpgFormat implements Config.ConfigEnum { /** Value for openpgp */ OPENPGP("openpgp"), //$NON-NLS-1$ /** Value for x509 */ - X509("x509"); //$NON-NLS-1$ + X509("x509"), //$NON-NLS-1$ + /** + * Value for ssh. + * + * @since 7.0 + */ + SSH("ssh"); //$NON-NLS-1$ private final String configValue; @@ -55,26 +61,11 @@ public String toConfigValue() { private final boolean forceAnnotated; - /** - * Create a {@link GpgConfig} with the given parameters and default - * {@code true} for signing commits and {@code false} for tags. - * - * @param keySpec - * to use - * @param format - * to use - * @param gpgProgram - * to use - * @since 5.11 - */ - public GpgConfig(String keySpec, GpgFormat format, String gpgProgram) { - keyFormat = format; - signingKey = keySpec; - program = gpgProgram; - signCommits = true; - signAllTags = false; - forceAnnotated = false; - } + private final String sshDefaultKeyCommand; + + private final String sshAllowedSignersFile; + + private final String sshRevocationFile; /** * Create a new GPG config that reads the configuration from config. @@ -83,18 +74,18 @@ public GpgConfig(String keySpec, GpgFormat format, String gpgProgram) { * the config to read from */ public GpgConfig(Config config) { - keyFormat = config.getEnum(GpgFormat.values(), - ConfigConstants.CONFIG_GPG_SECTION, null, + keyFormat = config.getEnum(ConfigConstants.CONFIG_GPG_SECTION, null, ConfigConstants.CONFIG_KEY_FORMAT, GpgFormat.OPENPGP); signingKey = config.getString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_SIGNINGKEY); String exe = config.getString(ConfigConstants.CONFIG_GPG_SECTION, keyFormat.toConfigValue(), ConfigConstants.CONFIG_KEY_PROGRAM); - if (exe == null) { + if (exe == null && GpgFormat.OPENPGP.equals(keyFormat)) { exe = config.getString(ConfigConstants.CONFIG_GPG_SECTION, null, ConfigConstants.CONFIG_KEY_PROGRAM); } + program = exe; signCommits = config.getBoolean(ConfigConstants.CONFIG_COMMIT_SECTION, ConfigConstants.CONFIG_KEY_GPGSIGN, false); @@ -102,6 +93,17 @@ public GpgConfig(Config config) { ConfigConstants.CONFIG_KEY_GPGSIGN, false); forceAnnotated = config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION, ConfigConstants.CONFIG_KEY_FORCE_SIGN_ANNOTATED, false); + sshDefaultKeyCommand = config.getString( + ConfigConstants.CONFIG_GPG_SECTION, + ConfigConstants.CONFIG_SSH_SUBSECTION, + ConfigConstants.CONFIG_KEY_SSH_DEFAULT_KEY_COMMAND); + sshAllowedSignersFile = config.getString( + ConfigConstants.CONFIG_GPG_SECTION, + ConfigConstants.CONFIG_SSH_SUBSECTION, + ConfigConstants.CONFIG_KEY_SSH_ALLOWED_SIGNERS_FILE); + sshRevocationFile = config.getString(ConfigConstants.CONFIG_GPG_SECTION, + ConfigConstants.CONFIG_SSH_SUBSECTION, + ConfigConstants.CONFIG_KEY_SSH_REVOCATION_FILE); } /** @@ -165,4 +167,37 @@ public boolean isSignAllTags() { public boolean isSignAnnotated() { return forceAnnotated; } + + /** + * Retrieves the value of git config {@code gpg.ssh.defaultKeyCommand}. + * + * @return the value of {@code gpg.ssh.defaultKeyCommand} + * + * @since 7.1 + */ + public String getSshDefaultKeyCommand() { + return sshDefaultKeyCommand; + } + + /** + * Retrieves the value of git config {@code gpg.ssh.allowedSignersFile}. + * + * @return the value of {@code gpg.ssh.allowedSignersFile} + * + * @since 7.1 + */ + public String getSshAllowedSignersFile() { + return sshAllowedSignersFile; + } + + /** + * Retrieves the value of git config {@code gpg.ssh.revocationFile}. + * + * @return the value of {@code gpg.ssh.revocationFile} + * + * @since 7.1 + */ + public String getSshRevocationFile() { + return sshRevocationFile; + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java deleted file mode 100644 index 074f465..0000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgObjectSigner.java +++ /dev/null
@@ -1,95 +0,0 @@ -/* - * 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.lib; - -import org.eclipse.jgit.annotations.NonNull; -import org.eclipse.jgit.annotations.Nullable; -import org.eclipse.jgit.api.errors.CanceledException; -import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException; -import org.eclipse.jgit.transport.CredentialsProvider; - -/** - * Creates GPG signatures for Git objects. - * - * @since 5.11 - */ -public interface GpgObjectSigner { - - /** - * Signs the specified object. - * - * <p> - * Implementors should obtain the payload for signing from the specified - * object via {@link ObjectBuilder#build()} and create a proper - * {@link GpgSignature}. The generated signature must be set on the - * specified {@code object} (see - * {@link ObjectBuilder#setGpgSignature(GpgSignature)}). - * </p> - * <p> - * Any existing signature on the object must be discarded prior obtaining - * the payload via {@link ObjectBuilder#build()}. - * </p> - * - * @param object - * the object to sign (must not be {@code null} and must be - * complete to allow proper calculation of payload) - * @param gpgSigningKey - * the signing key to locate (passed as is to the GPG signing - * tool as is; eg., value of <code>user.signingkey</code>) - * @param committer - * the signing identity (to help with key lookup in case signing - * key is not specified) - * @param credentialsProvider - * provider to use when querying for signing key credentials (eg. - * passphrase) - * @param config - * GPG settings from the git config - * @throws CanceledException - * when signing was canceled (eg., user aborted when entering - * passphrase) - * @throws UnsupportedSigningFormatException - * if a config is given and the wanted key format is not - * supported - */ - void signObject(@NonNull ObjectBuilder object, - @Nullable String gpgSigningKey, @NonNull PersonIdent committer, - CredentialsProvider credentialsProvider, GpgConfig config) - throws CanceledException, UnsupportedSigningFormatException; - - /** - * Indicates if a signing key is available for the specified committer - * and/or signing key. - * - * @param gpgSigningKey - * the signing key to locate (passed as is to the GPG signing - * tool as is; eg., value of <code>user.signingkey</code>) - * @param committer - * the signing identity (to help with key lookup in case signing - * key is not specified) - * @param credentialsProvider - * provider to use when querying for signing key credentials (eg. - * passphrase) - * @param config - * GPG settings from the git config - * @return <code>true</code> if a signing key is available, - * <code>false</code> otherwise - * @throws CanceledException - * when signing was canceled (eg., user aborted when entering - * passphrase) - * @throws UnsupportedSigningFormatException - * if a config is given and the wanted key format is not - * supported - */ - public abstract boolean canLocateSigningKey(@Nullable String gpgSigningKey, - @NonNull PersonIdent committer, - CredentialsProvider credentialsProvider, GpgConfig config) - throws CanceledException, UnsupportedSigningFormatException; - -}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifier.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifier.java deleted file mode 100644 index 91c9bab..0000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifier.java +++ /dev/null
@@ -1,184 +0,0 @@ -/* - * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.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 - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.lib; - -import java.io.IOException; -import java.util.Date; - -import org.eclipse.jgit.annotations.NonNull; -import org.eclipse.jgit.annotations.Nullable; -import org.eclipse.jgit.api.errors.JGitInternalException; -import org.eclipse.jgit.revwalk.RevObject; - -/** - * A {@code GpgSignatureVerifier} can verify GPG signatures on git commits and - * tags. - * - * @since 5.11 - */ -public interface GpgSignatureVerifier { - - /** - * Verifies the signature on a signed commit or tag. - * - * @param object - * to verify - * @param config - * the {@link GpgConfig} to use - * @return a {@link SignatureVerification} describing the outcome of the - * verification, or {@code null} if the object was not signed - * @throws IOException - * if an error occurs getting a public key - * @throws org.eclipse.jgit.api.errors.JGitInternalException - * if signature verification fails - */ - @Nullable - SignatureVerification verifySignature(@NonNull RevObject object, - @NonNull GpgConfig config) throws IOException; - - /** - * Verifies a given signature for given data. - * - * @param config - * the {@link GpgConfig} - * @param data - * the signature is for - * @param signatureData - * the ASCII-armored signature - * @return a {@link SignatureVerification} describing the outcome - * @throws IOException - * if the signature cannot be parsed - * @throws JGitInternalException - * if signature verification fails - * @since 6.9 - */ - default SignatureVerification verify(@NonNull GpgConfig config, byte[] data, - byte[] signatureData) throws IOException { - // Default implementation for backwards compatibility; override as - // appropriate - return verify(data, signatureData); - } - - /** - * Verifies a given signature for given data. - * - * @param data - * the signature is for - * @param signatureData - * the ASCII-armored signature - * @return a {@link SignatureVerification} describing the outcome - * @throws IOException - * if the signature cannot be parsed - * @throws JGitInternalException - * if signature verification fails - * @deprecated since 6.9, use {@link #verify(GpgConfig, byte[], byte[])} - * instead - */ - @Deprecated - public SignatureVerification verify(byte[] data, byte[] signatureData) - throws IOException; - - /** - * Retrieves the name of this verifier. This should be a short string - * identifying the engine that verified the signature, like "gpg" if GPG is - * used, or "bc" for a BouncyCastle implementation. - * - * @return the name - */ - @NonNull - String getName(); - - /** - * A {@link GpgSignatureVerifier} may cache public keys to speed up - * verifying signatures on multiple objects. This clears this cache, if any. - */ - void clear(); - - /** - * A {@code SignatureVerification} returns data about a (positively or - * negatively) verified signature. - */ - interface SignatureVerification { - - // Data about the signature. - - @NonNull - Date getCreationDate(); - - // Data from the signature used to find a public key. - - /** - * Obtains the signer as stored in the signature, if known. - * - * @return the signer, or {@code null} if unknown - */ - String getSigner(); - - /** - * Obtains the short or long fingerprint of the public key as stored in - * the signature, if known. - * - * @return the fingerprint, or {@code null} if unknown - */ - String getKeyFingerprint(); - - // Some information about the found public key. - - /** - * Obtains the OpenPGP user ID associated with the key. - * - * @return the user id, or {@code null} if unknown - */ - String getKeyUser(); - - /** - * Tells whether the public key used for this signature verification was - * expired when the signature was created. - * - * @return {@code true} if the key was expired already, {@code false} - * otherwise - */ - boolean isExpired(); - - /** - * Obtains the trust level of the public key used to verify the - * signature. - * - * @return the trust level - */ - @NonNull - TrustLevel getTrustLevel(); - - // The verification result. - - /** - * Tells whether the signature verification was successful. - * - * @return {@code true} if the signature was verified successfully; - * {@code false} if not. - */ - boolean getVerified(); - - /** - * Obtains a human-readable message giving additional information about - * the outcome of the verification. - * - * @return the message, or {@code null} if none set. - */ - String getMessage(); - } - - /** - * The owner's trust in a public key. - */ - enum TrustLevel { - UNKNOWN, NEVER, MARGINAL, FULL, ULTIMATE - } -}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java deleted file mode 100644 index 59775c4..0000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignatureVerifierFactory.java +++ /dev/null
@@ -1,92 +0,0 @@ -/* - * Copyright (C) 2021, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.lib; - -import java.util.Iterator; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A {@code GpgSignatureVerifierFactory} creates {@link GpgSignatureVerifier} instances. - * - * @since 5.11 - */ -public abstract class GpgSignatureVerifierFactory { - - private static final Logger LOG = LoggerFactory - .getLogger(GpgSignatureVerifierFactory.class); - - private static class DefaultFactory { - - private static volatile GpgSignatureVerifierFactory defaultFactory = loadDefault(); - - private static GpgSignatureVerifierFactory loadDefault() { - try { - ServiceLoader<GpgSignatureVerifierFactory> loader = ServiceLoader - .load(GpgSignatureVerifierFactory.class); - Iterator<GpgSignatureVerifierFactory> iter = loader.iterator(); - if (iter.hasNext()) { - return iter.next(); - } - } catch (ServiceConfigurationError e) { - LOG.error(e.getMessage(), e); - } - return null; - } - - private DefaultFactory() { - // No instantiation - } - - public static GpgSignatureVerifierFactory getDefault() { - return defaultFactory; - } - - /** - * Sets the default factory. - * - * @param factory - * the new default factory - */ - public static void setDefault(GpgSignatureVerifierFactory factory) { - defaultFactory = factory; - } - } - - /** - * Retrieves the default factory. - * - * @return the default factory or {@code null} if none set - */ - public static GpgSignatureVerifierFactory getDefault() { - return DefaultFactory.getDefault(); - } - - /** - * Sets the default factory. - * - * @param factory - * the new default factory - */ - public static void setDefault(GpgSignatureVerifierFactory factory) { - DefaultFactory.setDefault(factory); - } - - /** - * Creates a new {@link GpgSignatureVerifier}. - * - * @return the new {@link GpgSignatureVerifier} - */ - public abstract GpgSignatureVerifier getVerifier(); - -}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java deleted file mode 100644 index b25a61b..0000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java +++ /dev/null
@@ -1,141 +0,0 @@ -/* - * Copyright (C) 2018, 2022 Salesforce and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.lib; - -import java.util.Iterator; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; - -import org.eclipse.jgit.annotations.NonNull; -import org.eclipse.jgit.annotations.Nullable; -import org.eclipse.jgit.api.errors.CanceledException; -import org.eclipse.jgit.transport.CredentialsProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Creates GPG signatures for Git objects. - * - * @since 5.3 - */ -public abstract class GpgSigner { - - private static final Logger LOG = LoggerFactory.getLogger(GpgSigner.class); - - private static class DefaultSigner { - - private static volatile GpgSigner defaultSigner = loadGpgSigner(); - - private static GpgSigner loadGpgSigner() { - try { - ServiceLoader<GpgSigner> loader = ServiceLoader - .load(GpgSigner.class); - Iterator<GpgSigner> iter = loader.iterator(); - if (iter.hasNext()) { - return iter.next(); - } - } catch (ServiceConfigurationError e) { - LOG.error(e.getMessage(), e); - } - return null; - } - - private DefaultSigner() { - // No instantiation - } - - public static GpgSigner getDefault() { - return defaultSigner; - } - - public static void setDefault(GpgSigner signer) { - defaultSigner = signer; - } - } - - /** - * Get the default signer, or <code>null</code>. - * - * @return the default signer, or <code>null</code>. - */ - public static GpgSigner getDefault() { - return DefaultSigner.getDefault(); - } - - /** - * Set the default signer. - * - * @param signer - * the new default signer, may be <code>null</code> to select no - * default. - */ - public static void setDefault(GpgSigner signer) { - DefaultSigner.setDefault(signer); - } - - /** - * Signs the specified commit. - * - * <p> - * Implementors should obtain the payload for signing from the specified - * commit via {@link CommitBuilder#build()} and create a proper - * {@link GpgSignature}. The generated signature must be set on the - * specified {@code commit} (see - * {@link CommitBuilder#setGpgSignature(GpgSignature)}). - * </p> - * <p> - * Any existing signature on the commit must be discarded prior obtaining - * the payload via {@link CommitBuilder#build()}. - * </p> - * - * @param commit - * the commit to sign (must not be <code>null</code> and must be - * complete to allow proper calculation of payload) - * @param gpgSigningKey - * the signing key to locate (passed as is to the GPG signing - * tool as is; eg., value of <code>user.signingkey</code>) - * @param committer - * the signing identity (to help with key lookup in case signing - * key is not specified) - * @param credentialsProvider - * provider to use when querying for signing key credentials (eg. - * passphrase) - * @throws CanceledException - * when signing was canceled (eg., user aborted when entering - * passphrase) - */ - public abstract void sign(@NonNull CommitBuilder commit, - @Nullable String gpgSigningKey, @NonNull PersonIdent committer, - CredentialsProvider credentialsProvider) throws CanceledException; - - /** - * Indicates if a signing key is available for the specified committer - * and/or signing key. - * - * @param gpgSigningKey - * the signing key to locate (passed as is to the GPG signing - * tool as is; eg., value of <code>user.signingkey</code>) - * @param committer - * the signing identity (to help with key lookup in case signing - * key is not specified) - * @param credentialsProvider - * provider to use when querying for signing key credentials (eg. - * passphrase) - * @return <code>true</code> if a signing key is available, - * <code>false</code> otherwise - * @throws CanceledException - * when signing was canceled (eg., user aborted when entering - * passphrase) - */ - public abstract boolean canLocateSigningKey(@Nullable String gpgSigningKey, - @NonNull PersonIdent committer, - CredentialsProvider credentialsProvider) throws CanceledException; - -}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java index 8e965c5..a99c647 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -639,7 +639,7 @@ public boolean diff(ProgressMonitor monitor, int estWorkTreeSize, // submodule repository in .git/modules doesn't // exist yet it isn't "missing". File gitDir = new File( - new File(repository.getDirectory(), + new File(repository.getCommonDirectory(), Constants.MODULES), subRepoPath); if (!gitDir.isDirectory()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java index 1c31263..1b455b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
@@ -15,6 +15,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.nio.ByteBuffer; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.InvalidObjectIdException; @@ -152,6 +153,22 @@ public static final ObjectId fromRaw(byte[] bs, int p) { } /** + * Convert an ObjectId from raw binary representation + * + * @param bb + * a bytebuffer with the objectid encoded as 5 consecutive ints. + * This is the reverse of {@link ObjectId#copyRawTo(ByteBuffer)} + * + * @return the converted object id. + * + * @since 7.0 + */ + public static final ObjectId fromRaw(ByteBuffer bb) { + return new ObjectId(bb.getInt(), bb.getInt(), bb.getInt(), bb.getInt(), + bb.getInt()); + } + + /** * Convert an ObjectId from raw binary representation. * * @param is
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java index 3ba055a..50f4a83 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -12,10 +12,15 @@ package org.eclipse.jgit.lib; +import static java.time.ZoneOffset.UTC; + import java.io.Serializable; -import java.text.SimpleDateFormat; +import java.time.DateTimeException; import java.time.Instant; import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.Locale; import java.util.TimeZone; @@ -40,7 +45,9 @@ public class PersonIdent implements Serializable { * timezone offset as in {@link #getTimeZoneOffset()}. * @return time zone object for the given offset. * @since 4.1 + * @deprecated use {@link #getZoneId(int)} instead */ + @Deprecated(since = "7.2") public static TimeZone getTimeZone(int tzOffset) { StringBuilder tzId = new StringBuilder(8); tzId.append("GMT"); //$NON-NLS-1$ @@ -49,6 +56,21 @@ public static TimeZone getTimeZone(int tzOffset) { } /** + * Translate a minutes offset into a ZoneId + * + * @param tzOffset as minutes east of UTC + * @return a ZoneId for this offset (UTC if invalid) + * @since 7.1 + */ + public static ZoneId getZoneId(int tzOffset) { + try { + return ZoneOffset.ofHoursMinutes(tzOffset / 60, tzOffset % 60); + } catch (DateTimeException e) { + return UTC; + } + } + + /** * Format a timezone offset. * * @param r @@ -121,13 +143,17 @@ public static void appendSanitized(StringBuilder r, String str) { } } + // Write offsets as [+-]HHMM + private static final DateTimeFormatter OFFSET_FORMATTER = DateTimeFormatter + .ofPattern("Z", Locale.US); //$NON-NLS-1$ + private final String name; private final String emailAddress; - private final long when; + private final Instant when; - private final int tzOffset; + private final ZoneId tzOffset; /** * Creates new PersonIdent from config info in repository, with current time. @@ -160,7 +186,7 @@ public PersonIdent(PersonIdent pi) { * a {@link java.lang.String} object. */ public PersonIdent(String aName, String aEmailAddress) { - this(aName, aEmailAddress, SystemReader.getInstance().getCurrentTime()); + this(aName, aEmailAddress, SystemReader.getInstance().now()); } /** @@ -177,7 +203,7 @@ public PersonIdent(String aName, String aEmailAddress) { */ public PersonIdent(String aName, String aEmailAddress, ProposedTimestamp when) { - this(aName, aEmailAddress, when.millis()); + this(aName, aEmailAddress, when.instant()); } /** @@ -189,8 +215,25 @@ public PersonIdent(String aName, String aEmailAddress, * local time * @param tz * time zone + * @deprecated Use {@link #PersonIdent(PersonIdent, Instant, ZoneId)} instead. */ + @Deprecated(since = "7.1") public PersonIdent(PersonIdent pi, Date when, TimeZone tz) { + this(pi.getName(), pi.getEmailAddress(), when.toInstant(), tz.toZoneId()); + } + + /** + * Copy a PersonIdent, but alter the clone's time stamp + * + * @param pi + * original {@link org.eclipse.jgit.lib.PersonIdent} + * @param when + * local time + * @param tz + * time zone offset + * @since 7.1 + */ + public PersonIdent(PersonIdent pi, Instant when, ZoneId tz) { this(pi.getName(), pi.getEmailAddress(), when, tz); } @@ -202,9 +245,12 @@ public PersonIdent(PersonIdent pi, Date when, TimeZone tz) { * original {@link org.eclipse.jgit.lib.PersonIdent} * @param aWhen * local time + * @deprecated Use the variant with an Instant instead */ + @Deprecated(since = "7.1") public PersonIdent(PersonIdent pi, Date aWhen) { - this(pi.getName(), pi.getEmailAddress(), aWhen.getTime(), pi.tzOffset); + this(pi.getName(), pi.getEmailAddress(), aWhen.toInstant(), + pi.tzOffset); } /** @@ -218,7 +264,7 @@ public PersonIdent(PersonIdent pi, Date aWhen) { * @since 6.1 */ public PersonIdent(PersonIdent pi, Instant aWhen) { - this(pi.getName(), pi.getEmailAddress(), aWhen.toEpochMilli(), pi.tzOffset); + this(pi.getName(), pi.getEmailAddress(), aWhen, pi.tzOffset); } /** @@ -230,11 +276,12 @@ public PersonIdent(PersonIdent pi, Instant aWhen) { * local time stamp * @param aTZ * time zone + * @deprecated Use the variant with Instant and ZoneId instead */ + @Deprecated(since = "7.1") public PersonIdent(final String aName, final String aEmailAddress, final Date aWhen, final TimeZone aTZ) { - this(aName, aEmailAddress, aWhen.getTime(), aTZ.getOffset(aWhen - .getTime()) / (60 * 1000)); + this(aName, aEmailAddress, aWhen.toInstant(), aTZ.toZoneId()); } /** @@ -252,10 +299,16 @@ public PersonIdent(final String aName, final String aEmailAddress, */ public PersonIdent(final String aName, String aEmailAddress, Instant aWhen, ZoneId zoneId) { - this(aName, aEmailAddress, aWhen.toEpochMilli(), - TimeZone.getTimeZone(zoneId) - .getOffset(aWhen - .toEpochMilli()) / (60 * 1000)); + if (aName == null) + throw new IllegalArgumentException( + JGitText.get().personIdentNameNonNull); + if (aEmailAddress == null) + throw new IllegalArgumentException( + JGitText.get().personIdentEmailNonNull); + name = aName; + emailAddress = aEmailAddress; + when = aWhen; + tzOffset = zoneId; } /** @@ -267,15 +320,18 @@ public PersonIdent(final String aName, String aEmailAddress, Instant aWhen, * local time stamp * @param aTZ * time zone + * @deprecated Use the variant with Instant and ZoneId instead */ + @Deprecated(since = "7.1") public PersonIdent(PersonIdent pi, long aWhen, int aTZ) { - this(pi.getName(), pi.getEmailAddress(), aWhen, aTZ); + this(pi.getName(), pi.getEmailAddress(), Instant.ofEpochMilli(aWhen), + getZoneId(aTZ)); } private PersonIdent(final String aName, final String aEmailAddress, - long when) { + Instant when) { this(aName, aEmailAddress, when, SystemReader.getInstance() - .getTimezone(when)); + .getTimeZoneAt(when)); } private PersonIdent(UserConfig config) { @@ -298,19 +354,12 @@ private PersonIdent(UserConfig config) { * local time stamp * @param aTZ * time zone + * @deprecated Use the variant with Instant and ZoneId instead */ + @Deprecated(since = "7.1") public PersonIdent(final String aName, final String aEmailAddress, final long aWhen, final int aTZ) { - if (aName == null) - throw new IllegalArgumentException( - JGitText.get().personIdentNameNonNull); - if (aEmailAddress == null) - throw new IllegalArgumentException( - JGitText.get().personIdentEmailNonNull); - name = aName; - emailAddress = aEmailAddress; - when = aWhen; - tzOffset = aTZ; + this(aName, aEmailAddress, Instant.ofEpochMilli(aWhen), getZoneId(aTZ)); } /** @@ -335,9 +384,12 @@ public String getEmailAddress() { * Get timestamp * * @return timestamp + * + * @deprecated Use getWhenAsInstant instead */ + @Deprecated(since = "7.1") public Date getWhen() { - return new Date(when); + return Date.from(when); } /** @@ -347,16 +399,19 @@ public Date getWhen() { * @since 6.1 */ public Instant getWhenAsInstant() { - return Instant.ofEpochMilli(when); + return when; } /** * Get this person's declared time zone * * @return this person's declared time zone; null if time zone is unknown. + * + * @deprecated Use getZoneId instead */ + @Deprecated(since = "7.1") public TimeZone getTimeZone() { - return getTimeZone(tzOffset); + return TimeZone.getTimeZone(tzOffset); } /** @@ -366,7 +421,17 @@ public TimeZone getTimeZone() { * @since 6.1 */ public ZoneId getZoneId() { - return getTimeZone().toZoneId(); + return tzOffset; + } + + /** + * Return the offset in this timezone at the specific time + * + * @return the offset + * @since 7.1 + */ + public ZoneOffset getZoneOffset() { + return tzOffset.getRules().getOffset(when); } /** @@ -374,9 +439,11 @@ public ZoneId getZoneId() { * * @return this person's declared time zone as minutes east of UTC. If the * timezone is to the west of UTC it is negative. + * @deprecated Use {@link #getZoneOffset()} and read minutes from there */ + @Deprecated(since = "7.1") public int getTimeZoneOffset() { - return tzOffset; + return getZoneOffset().getTotalSeconds() / 60; } /** @@ -388,7 +455,7 @@ public int getTimeZoneOffset() { public int hashCode() { int hc = getEmailAddress().hashCode(); hc *= 31; - hc += (int) (when / 1000L); + hc += when.hashCode(); return hc; } @@ -398,7 +465,9 @@ public boolean equals(Object o) { final PersonIdent p = (PersonIdent) o; return getName().equals(p.getName()) && getEmailAddress().equals(p.getEmailAddress()) - && when / 1000L == p.when / 1000L; + // commmit timestamps are stored with 1 second precision + && when.truncatedTo(ChronoUnit.SECONDS) + .equals(p.when.truncatedTo(ChronoUnit.SECONDS)); } return false; } @@ -414,9 +483,9 @@ public String toExternalString() { r.append(" <"); //$NON-NLS-1$ appendSanitized(r, getEmailAddress()); r.append("> "); //$NON-NLS-1$ - r.append(when / 1000); + r.append(when.toEpochMilli() / 1000); r.append(' '); - appendTimezone(r, tzOffset); + r.append(OFFSET_FORMATTER.format(getZoneOffset())); return r.toString(); } @@ -424,19 +493,16 @@ public String toExternalString() { @SuppressWarnings("nls") public String toString() { final StringBuilder r = new StringBuilder(); - final SimpleDateFormat dtfmt; - dtfmt = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy Z", Locale.US); - dtfmt.setTimeZone(getTimeZone()); - + DateTimeFormatter dtfmt = DateTimeFormatter + .ofPattern("EEE MMM d HH:mm:ss yyyy Z", Locale.US) //$NON-NLS-1$ + .withZone(tzOffset); r.append("PersonIdent["); r.append(getName()); r.append(", "); r.append(getEmailAddress()); r.append(", "); - r.append(dtfmt.format(Long.valueOf(when))); + r.append(dtfmt.format(when)); r.append("]"); - return r.toString(); } } -
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java index 9e05a39..49d5224 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -26,6 +26,7 @@ import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.api.PackRefsCommand; /** * Abstraction of name to {@link org.eclipse.jgit.lib.ObjectId} mapping. @@ -160,7 +161,7 @@ public Collection<String> getConflictingNames(String name) if (existing.startsWith(prefix)) conflicting.add(existing); - return conflicting; + return Collections.unmodifiableList(conflicting); } /** @@ -238,23 +239,6 @@ public boolean performsAtomicTransactions() { } /** - * Compatibility synonym for {@link #findRef(String)}. - * - * @param name - * the name of the reference. May be a short name which must be - * searched for using the standard {@link #SEARCH_PATH}. - * @return the reference (if it exists); else {@code null}. - * @throws IOException - * the reference space cannot be accessed. - * @deprecated Use {@link #findRef(String)} instead. - */ - @Deprecated - @Nullable - public final Ref getRef(String name) throws IOException { - return findRef(name); - } - - /** * Read a single reference. * <p> * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be @@ -372,6 +356,40 @@ public List<Ref> getRefs() throws IOException { } /** + * Get the reflog reader + * + * @param refName + * a {@link java.lang.String} object. + * @return a {@link org.eclipse.jgit.lib.ReflogReader} for the supplied + * refname, or {@code null} if the named ref does not exist. + * @throws java.io.IOException + * the ref could not be accessed. + * @since 7.2 + */ + @Nullable + public ReflogReader getReflogReader(String refName) throws IOException { + Ref ref = exactRef(refName); + if (ref == null) { + return null; + } + return getReflogReader(ref); + } + + /** + * Get the reflog reader. + * + * @param ref + * a Ref + * @return a {@link org.eclipse.jgit.lib.ReflogReader} for the supplied ref. + * @throws IOException + * if an IO error occurred + * @since 7.2 + */ + @NonNull + public abstract ReflogReader getReflogReader(@NonNull Ref ref) + throws IOException; + + /** * Get a section of the reference namespace. * * @param prefix @@ -610,4 +628,22 @@ public static Ref findRef(Map<String, Ref> map, String name) { } return null; } + + /** + * Optimize pack ref storage. + * + * @param pm + * a progress monitor + * + * @param packRefs + * {@link PackRefsCommand} to control ref packing behavior + * + * @throws java.io.IOException + * if an IO error occurred + * @since 7.1 + */ + public void packRefs(ProgressMonitor pm, PackRefsCommand packRefs) + throws IOException { + // nothing + } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 4722e29..c9dc6da 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -26,6 +26,8 @@ import java.io.OutputStream; import java.io.UncheckedIOException; import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.LinkOption; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -33,10 +35,12 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import org.eclipse.jgit.annotations.NonNull; @@ -113,9 +117,12 @@ public static ListenerList getGlobalListenerList() { final AtomicLong closedAt = new AtomicLong(); - /** Metadata directory holding the repository's critical files. */ + /** $GIT_DIR: metadata directory holding the repository's critical files. */ private final File gitDir; + /** $GIT_COMMON_DIR: metadata directory holding the common repository's critical files. */ + private final File gitCommonDir; + /** File abstraction used to resolve paths. */ private final FS fs; @@ -129,6 +136,8 @@ public static ListenerList getGlobalListenerList() { private final String initialBranch; + private final AtomicReference<Boolean> caseInsensitiveWorktree = new AtomicReference<>(); + /** * Initialize a new repository instance. * @@ -137,6 +146,7 @@ public static ListenerList getGlobalListenerList() { */ protected Repository(BaseRepositoryBuilder options) { gitDir = options.getGitDir(); + gitCommonDir = options.getGitCommonDir(); fs = options.getFS(); workTree = options.getWorkTree(); indexFile = options.getIndexFile(); @@ -220,6 +230,16 @@ public File getDirectory() { public abstract String getIdentifier(); /** + * Get common dir. + * + * @return $GIT_COMMON_DIR: local common metadata directory; + * @since 7.0 + */ + public File getCommonDirectory() { + return gitCommonDir; + } + + /** * Get the object database which stores this repository's data. * * @return the object database which stores this repository's data. @@ -293,25 +313,6 @@ public FS getFS() { } /** - * Whether the specified object is stored in this repo or any of the known - * shared repositories. - * - * @param objectId - * a {@link org.eclipse.jgit.lib.AnyObjectId} object. - * @return true if the specified object is stored in this repo or any of the - * known shared repositories. - * @deprecated use {@code getObjectDatabase().has(objectId)} - */ - @Deprecated - public boolean hasObject(AnyObjectId objectId) { - try { - return getObjectDatabase().has(objectId); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** * Open an object from this repository. * <p> * This is a one-shot call interface which may be faster than allocating a @@ -1150,11 +1151,9 @@ public Map<String, Ref> getTags() { * new Ref object representing the same data as Ref, but isPeeled() * will be true and getPeeledObjectId will contain the peeled object * (or null). - * @deprecated use {@code getRefDatabase().peel(ref)} instead. */ - @Deprecated @NonNull - public Ref peel(Ref ref) { + private Ref peel(Ref ref) { try { return getRefDatabase().peel(ref); } catch (IOException e) { @@ -1584,6 +1583,40 @@ public File getWorkTree() throws NoWorkTreeException { } /** + * Tells whether the work tree is on a case-insensitive file system. + * + * @return {@code true} if the work tree is case-insensitive; {@code false} + * otherwise + * @throws NoWorkTreeException + * if the repository is bare + * @since 7.2 + */ + public boolean isWorkTreeCaseInsensitive() throws NoWorkTreeException { + Boolean flag = caseInsensitiveWorktree.get(); + if (flag == null) { + File directory = getWorkTree(); + // See if we can find ".git" also as ".GIT". + File dotGit = new File(directory, Constants.DOT_GIT); + if (Files.exists(dotGit.toPath(), LinkOption.NOFOLLOW_LINKS)) { + dotGit = new File(directory, + Constants.DOT_GIT.toUpperCase(Locale.ROOT)); + flag = Boolean.valueOf(Files.exists(dotGit.toPath(), + LinkOption.NOFOLLOW_LINKS)); + } else { + // Fall back to a mostly sane default. On Mac, HFS+ and APFS + // partitions are case-insensitive by default but can be + // configured to be case-sensitive. + SystemReader system = SystemReader.getInstance(); + flag = Boolean.valueOf(system.isWindows() || system.isMacOS()); + } + if (!caseInsensitiveWorktree.compareAndSet(null, flag)) { + flag = caseInsensitiveWorktree.get(); + } + } + return flag.booleanValue(); + } + + /** * Force a scan for changed refs. Fires an IndexChangedEvent(false) if * changes are detected. * @@ -1699,10 +1732,13 @@ public void setGitwebDescription(@Nullable String description) * @throws java.io.IOException * the ref could not be accessed. * @since 3.0 + * @deprecated use {@code #getRefDatabase().getReflogReader(String)} instead */ + @Deprecated(since = "7.2") @Nullable - public abstract ReflogReader getReflogReader(String refName) - throws IOException; + public ReflogReader getReflogReader(String refName) throws IOException { + return getRefDatabase().getReflogReader(refName); + } /** * Get the reflog reader. Subclasses should override this method and provide @@ -1710,15 +1746,17 @@ public abstract ReflogReader getReflogReader(String refName) * * @param ref * a Ref - * @return a {@link org.eclipse.jgit.lib.ReflogReader} for the supplied ref, - * or {@code null} if the ref does not exist. + * @return a {@link org.eclipse.jgit.lib.ReflogReader} for the supplied ref. * @throws IOException * if an IO error occurred * @since 5.13.2 + * @deprecated use {@code #getRefDatabase().getReflogReader(Ref)} instead */ - public @Nullable ReflogReader getReflogReader(@NonNull Ref ref) + @Deprecated(since = "7.2") + @NonNull + public ReflogReader getReflogReader(@NonNull Ref ref) throws IOException { - return getReflogReader(ref.getName()); + return getRefDatabase().getReflogReader(ref); } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java index 6288447..1836654 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -450,10 +450,21 @@ public String toString() { * Git directory. */ public static boolean isGitRepository(File dir, FS fs) { - return fs.resolve(dir, Constants.OBJECTS).exists() - && fs.resolve(dir, "refs").exists() //$NON-NLS-1$ - && (fs.resolve(dir, Constants.REFTABLE).exists() - || isValidHead(new File(dir, Constants.HEAD))); + // check if common-dir available or fallback to git-dir + File commonDir; + try { + commonDir = fs.getCommonDir(dir); + } catch (IOException e) { + commonDir = null; + } + if (commonDir == null) { + commonDir = dir; + } + return fs.resolve(commonDir, Constants.OBJECTS).exists() + && fs.resolve(commonDir, "refs").exists() //$NON-NLS-1$ + && (fs.resolve(commonDir, Constants.REFTABLE).exists() + || isValidHead( + new File(commonDir, Constants.HEAD))); } private static boolean isValidHead(File head) { @@ -496,15 +507,31 @@ private static String readFirstLine(File head) { * null if there is no suitable match. */ public static File resolve(File directory, FS fs) { - if (isGitRepository(directory, fs)) + // the folder itself + if (isGitRepository(directory, fs)) { return directory; - if (isGitRepository(new File(directory, Constants.DOT_GIT), fs)) - return new File(directory, Constants.DOT_GIT); - - final String name = directory.getName(); - final File parent = directory.getParentFile(); - if (isGitRepository(new File(parent, name + Constants.DOT_GIT_EXT), fs)) - return new File(parent, name + Constants.DOT_GIT_EXT); + } + // the .git subfolder or file (reference) + File dotDir = new File(directory, Constants.DOT_GIT); + if (dotDir.isFile()) { + try { + File refDir = BaseRepositoryBuilder.getSymRef(directory, + dotDir, fs); + if (refDir != null && isGitRepository(refDir, fs)) { + return refDir; + } + } catch (IOException ignored) { + // Continue searching if gitdir ref isn't found + } + } else if (isGitRepository(dotDir, fs)) { + return dotDir; + } + // the folder extended with .git (bare) + File bareDir = new File(directory.getParentFile(), + directory.getName() + Constants.DOT_GIT_EXT); + if (isGitRepository(bareDir, fs)) { + return bareDir; + } return null; } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifier.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifier.java new file mode 100644 index 0000000..2ce2708 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifier.java
@@ -0,0 +1,106 @@ +/* + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import java.io.IOException; +import java.util.Date; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.errors.JGitInternalException; + +/** + * A {@code SignatureVerifier} can verify signatures on git commits and tags. + * + * @since 7.0 + */ +public interface SignatureVerifier { + + /** + * Verifies a given signature for given data. + * + * @param repository + * the {@link Repository} the data comes from. + * @param config + * the {@link GpgConfig} + * @param data + * the signature is for + * @param signatureData + * the ASCII-armored signature + * @return a {@link SignatureVerification} describing the outcome + * @throws IOException + * if the signature cannot be parsed + * @throws JGitInternalException + * if signature verification fails + */ + SignatureVerification verify(@NonNull Repository repository, + @NonNull GpgConfig config, byte[] data, byte[] signatureData) + throws IOException; + + /** + * Retrieves the name of this verifier. This should be a short string + * identifying the engine that verified the signature, like "gpg" if GPG is + * used, or "bc" for a BouncyCastle implementation. + * + * @return the name + */ + @NonNull + String getName(); + + /** + * A {@link SignatureVerifier} may cache public keys to speed up + * verifying signatures on multiple objects. This clears this cache, if any. + */ + void clear(); + + /** + * A {@code SignatureVerification} returns data about a (positively or + * negatively) verified signature. + * + * @param verifierName + * the name of the verifier that created this verification result + * @param creationDate + * date and time the signature was created + * @param signer + * the signer as stored in the signature, or {@code null} if + * unknown + * @param keyFingerprint + * fingerprint of the public key, or {@code null} if unknown + * @param keyUser + * user associated with the key, or {@code null} if unknown + * @param verified + * whether the signature verification was successful + * @param expired + * whether the public key used for this signature verification + * was expired when the signature was created + * @param trustLevel + * the trust level of the public key used to verify the signature + * @param message + * human-readable message giving additional information about the + * outcome of the verification, possibly {@code null} + */ + record SignatureVerification( + String verifierName, + Date creationDate, + String signer, + String keyFingerprint, + String keyUser, + boolean verified, + boolean expired, + @NonNull TrustLevel trustLevel, + String message) { + } + + /** + * The owner's trust in a public key. + */ + enum TrustLevel { + UNKNOWN, NEVER, MARGINAL, FULL, ULTIMATE + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifierFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifierFactory.java new file mode 100644 index 0000000..7844aba --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifierFactory.java
@@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import org.eclipse.jgit.annotations.NonNull; + +/** + * A factory for {@link SignatureVerifier}s. + * + * @since 7.0 + */ +public interface SignatureVerifierFactory { + + /** + * Tells what kind of {@link SignatureVerifier} this factory creates. + * + * @return the {@link GpgConfig.GpgFormat} of the signer + */ + @NonNull + GpgConfig.GpgFormat getType(); + + /** + * Creates a new instance of a {@link SignatureVerifier} that can produce + * signatures of type {@link #getType()}. + * + * @return a new {@link SignatureVerifier} + */ + @NonNull + SignatureVerifier create(); +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifiers.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifiers.java new file mode 100644 index 0000000..01c8422 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignatureVerifiers.java
@@ -0,0 +1,239 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.util.RawParseUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Manages the available signers. + * + * @since 7.0 + */ +public final class SignatureVerifiers { + + private static final Logger LOG = LoggerFactory.getLogger(SignatureVerifiers.class); + + private static final byte[] PGP_PREFIX = Constants.GPG_SIGNATURE_PREFIX + .getBytes(StandardCharsets.US_ASCII); + + private static final byte[] X509_PREFIX = Constants.CMS_SIGNATURE_PREFIX + .getBytes(StandardCharsets.US_ASCII); + + private static final byte[] SSH_PREFIX = Constants.SSH_SIGNATURE_PREFIX + .getBytes(StandardCharsets.US_ASCII); + + private static final Map<GpgConfig.GpgFormat, SignatureVerifierFactory> FACTORIES = loadSignatureVerifiers(); + + private static final Map<GpgConfig.GpgFormat, SignatureVerifier> VERIFIERS = new ConcurrentHashMap<>(); + + private static Map<GpgConfig.GpgFormat, SignatureVerifierFactory> loadSignatureVerifiers() { + Map<GpgConfig.GpgFormat, SignatureVerifierFactory> result = new EnumMap<>( + GpgConfig.GpgFormat.class); + try { + for (SignatureVerifierFactory factory : ServiceLoader + .load(SignatureVerifierFactory.class)) { + GpgConfig.GpgFormat format = factory.getType(); + SignatureVerifierFactory existing = result.get(format); + if (existing != null) { + LOG.warn("{}", //$NON-NLS-1$ + MessageFormat.format( + JGitText.get().signatureServiceConflict, + "SignatureVerifierFactory", format, //$NON-NLS-1$ + existing.getClass().getCanonicalName(), + factory.getClass().getCanonicalName())); + } else { + result.put(format, factory); + } + } + } catch (ServiceConfigurationError e) { + LOG.error(e.getMessage(), e); + } + return result; + } + + private SignatureVerifiers() { + // No instantiation + } + + /** + * Retrieves a {@link Signer} that can produce signatures of the given type + * {@code format}. + * + * @param format + * {@link GpgConfig.GpgFormat} the signer must support + * @return a {@link Signer}, or {@code null} if none is available + */ + public static SignatureVerifier get(@NonNull GpgConfig.GpgFormat format) { + return VERIFIERS.computeIfAbsent(format, f -> { + SignatureVerifierFactory factory = FACTORIES.get(format); + if (factory == null) { + return null; + } + return factory.create(); + }); + } + + /** + * Sets a specific signature verifier to use for a specific signature type. + * + * @param format + * signature type to set the {@code verifier} for + * @param verifier + * the {@link SignatureVerifier} to use for signatures of type + * {@code format}; if {@code null}, a default implementation, if + * available, may be used. + */ + public static void set(@NonNull GpgConfig.GpgFormat format, + SignatureVerifier verifier) { + SignatureVerifier previous; + if (verifier == null) { + previous = VERIFIERS.remove(format); + } else { + previous = VERIFIERS.put(format, verifier); + } + if (previous != null) { + previous.clear(); + } + } + + /** + * Verifies the signature on a signed commit or tag. + * + * @param repository + * the {@link Repository} the object is from + * @param config + * the {@link GpgConfig} to use + * @param object + * to verify + * @return a {@link SignatureVerifier.SignatureVerification} describing the + * outcome of the verification, or {@code null} if the object does + * not have a signature of a known type + * @throws IOException + * if an error occurs getting a public key + * @throws org.eclipse.jgit.api.errors.JGitInternalException + * if signature verification fails + */ + @Nullable + public static SignatureVerifier.SignatureVerification verify( + @NonNull Repository repository, @NonNull GpgConfig config, + @NonNull RevObject object) throws IOException { + if (object instanceof RevCommit) { + RevCommit commit = (RevCommit) object; + byte[] signatureData = commit.getRawGpgSignature(); + if (signatureData == null) { + return null; + } + byte[] raw = commit.getRawBuffer(); + // Now remove the GPG signature + byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' }; + int start = RawParseUtils.headerStart(header, raw, 0); + if (start < 0) { + return null; + } + int end = RawParseUtils.nextLfSkippingSplitLines(raw, start); + // start is at the beginning of the header's content + start -= header.length + 1; + // end is on the terminating LF; we need to skip that, too + if (end < raw.length) { + end++; + } + byte[] data = new byte[raw.length - (end - start)]; + System.arraycopy(raw, 0, data, 0, start); + System.arraycopy(raw, end, data, start, raw.length - end); + return verify(repository, config, data, signatureData); + } else if (object instanceof RevTag) { + RevTag tag = (RevTag) object; + byte[] signatureData = tag.getRawGpgSignature(); + if (signatureData == null) { + return null; + } + byte[] raw = tag.getRawBuffer(); + // The signature is just tacked onto the end of the message, which + // is last in the buffer. + byte[] data = Arrays.copyOfRange(raw, 0, + raw.length - signatureData.length); + return verify(repository, config, data, signatureData); + } + return null; + } + + /** + * Verifies a given signature for some give data. + * + * @param repository + * the {@link Repository} the object is from + * @param config + * the {@link GpgConfig} to use + * @param data + * to verify the signature of + * @param signature + * the given signature of the {@code data} + * @return a {@link SignatureVerifier.SignatureVerification} describing the + * outcome of the verification, or {@code null} if the signature + * type is unknown + * @throws IOException + * if an error occurs getting a public key + * @throws org.eclipse.jgit.api.errors.JGitInternalException + * if signature verification fails + */ + @Nullable + public static SignatureVerifier.SignatureVerification verify( + @NonNull Repository repository, @NonNull GpgConfig config, + byte[] data, byte[] signature) throws IOException { + GpgConfig.GpgFormat format = getFormat(signature); + if (format == null) { + return null; + } + SignatureVerifier verifier = get(format); + if (verifier == null) { + return null; + } + return verifier.verify(repository, config, data, signature); + } + + /** + * Determines the type of a given signature. + * + * @param signature + * to get the type of + * @return the signature type, or {@code null} if unknown + */ + @Nullable + public static GpgConfig.GpgFormat getFormat(byte[] signature) { + if (RawParseUtils.match(signature, 0, PGP_PREFIX) > 0) { + return GpgConfig.GpgFormat.OPENPGP; + } + if (RawParseUtils.match(signature, 0, X509_PREFIX) > 0) { + return GpgConfig.GpgFormat.X509; + } + if (RawParseUtils.match(signature, 0, SSH_PREFIX) > 0) { + return GpgConfig.GpgFormat.SSH; + } + return null; + } +} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Signer.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Signer.java new file mode 100644 index 0000000..3bb7464 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Signer.java
@@ -0,0 +1,139 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.errors.CanceledException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException; +import org.eclipse.jgit.transport.CredentialsProvider; + +/** + * Creates signatures for Git objects. + * + * @since 7.0 + */ +public interface Signer { + + /** + * Signs the specified object. + * + * <p> + * Implementors should obtain the payload for signing from the specified + * object via {@link ObjectBuilder#build()} and create a proper + * {@link GpgSignature}. The generated signature is set on the specified + * {@code object} (see {@link ObjectBuilder#setGpgSignature(GpgSignature)}). + * </p> + * <p> + * Any existing signature on the object must be discarded prior obtaining + * the payload via {@link ObjectBuilder#build()}. + * </p> + * + * @param repository + * {@link Repository} the object belongs to + * @param config + * GPG settings from the git config + * @param object + * the object to sign (must not be {@code null} and must be + * complete to allow proper calculation of payload) + * @param committer + * the signing identity (to help with key lookup in case signing + * key is not specified) + * @param signingKey + * if non-{@code null} overrides the signing key from the config + * @param credentialsProvider + * provider to use when querying for signing key credentials (eg. + * passphrase) + * @throws CanceledException + * when signing was canceled (eg., user aborted when entering + * passphrase) + * @throws IOException + * if an I/O error occurs + * @throws UnsupportedSigningFormatException + * if a config is given and the wanted key format is not + * supported + */ + default void signObject(@NonNull Repository repository, + @NonNull GpgConfig config, @NonNull ObjectBuilder object, + @NonNull PersonIdent committer, String signingKey, + CredentialsProvider credentialsProvider) + throws CanceledException, IOException, + UnsupportedSigningFormatException { + try { + object.setGpgSignature(sign(repository, config, object.build(), + committer, signingKey, credentialsProvider)); + } catch (UnsupportedEncodingException e) { + throw new JGitInternalException(e.getMessage(), e); + } + } + + /** + * Signs arbitrary data. + * + * @param repository + * {@link Repository} the signature is created in + * @param config + * GPG settings from the git config + * @param data + * the data to sign + * @param committer + * the signing identity (to help with key lookup in case signing + * key is not specified) + * @param signingKey + * if non-{@code null} overrides the signing key from the config + * @param credentialsProvider + * provider to use when querying for signing key credentials (eg. + * passphrase) + * @return the signature for {@code data} + * @throws CanceledException + * when signing was canceled (eg., user aborted when entering + * passphrase) + * @throws IOException + * if an I/O error occurs + * @throws UnsupportedSigningFormatException + * if a config is given and the wanted key format is not + * supported + */ + GpgSignature sign(@NonNull Repository repository, @NonNull GpgConfig config, + byte[] data, @NonNull PersonIdent committer, String signingKey, + CredentialsProvider credentialsProvider) throws CanceledException, + IOException, UnsupportedSigningFormatException; + + /** + * Indicates if a signing key is available for the specified committer + * and/or signing key. + * + * @param repository + * the current {@link Repository} + * @param config + * GPG settings from the git config + * @param committer + * the signing identity (to help with key lookup in case signing + * key is not specified) + * @param signingKey + * if non-{@code null} overrides the signing key from the config + * @param credentialsProvider + * provider to use when querying for signing key credentials (eg. + * passphrase) + * @return {@code true} if a signing key is available, {@code false} + * otherwise + * @throws CanceledException + * when signing was canceled (eg., user aborted when entering + * passphrase) + */ + boolean canLocateSigningKey(@NonNull Repository repository, + @NonNull GpgConfig config, @NonNull PersonIdent committer, + String signingKey, CredentialsProvider credentialsProvider) + throws CanceledException; + +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignerFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignerFactory.java new file mode 100644 index 0000000..125d25e --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SignerFactory.java
@@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import org.eclipse.jgit.annotations.NonNull; + +/** + * A factory for {@link Signer}s. + * + * @since 7.0 + */ +public interface SignerFactory { + + /** + * Tells what kind of {@link Signer} this factory creates. + * + * @return the {@link GpgConfig.GpgFormat} of the signer + */ + @NonNull + GpgConfig.GpgFormat getType(); + + /** + * Creates a new instance of a {@link Signer} that can produce signatures of + * type {@link #getType()}. + * + * @return a new {@link Signer} + */ + @NonNull + Signer create(); +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Signers.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Signers.java new file mode 100644 index 0000000..7771b07 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Signers.java
@@ -0,0 +1,101 @@ +/* + * Copyright (C) 2024 Thomas Wolf <twolf@apache.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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import java.text.MessageFormat; +import java.util.EnumMap; +import java.util.Map; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.internal.JGitText; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Manages the available signers. + * + * @since 7.0 + */ +public final class Signers { + + private static final Logger LOG = LoggerFactory.getLogger(Signers.class); + + private static final Map<GpgConfig.GpgFormat, SignerFactory> SIGNER_FACTORIES = loadSigners(); + + private static final Map<GpgConfig.GpgFormat, Signer> SIGNERS = new ConcurrentHashMap<>(); + + private static Map<GpgConfig.GpgFormat, SignerFactory> loadSigners() { + Map<GpgConfig.GpgFormat, SignerFactory> result = new EnumMap<>( + GpgConfig.GpgFormat.class); + try { + for (SignerFactory factory : ServiceLoader + .load(SignerFactory.class)) { + GpgConfig.GpgFormat format = factory.getType(); + SignerFactory existing = result.get(format); + if (existing != null) { + LOG.warn("{}", //$NON-NLS-1$ + MessageFormat.format( + JGitText.get().signatureServiceConflict, + "SignerFactory", format, //$NON-NLS-1$ + existing.getClass().getCanonicalName(), + factory.getClass().getCanonicalName())); + } else { + result.put(format, factory); + } + } + } catch (ServiceConfigurationError e) { + LOG.error(e.getMessage(), e); + } + return result; + } + + private Signers() { + // No instantiation + } + + /** + * Retrieves a {@link Signer} that can produce signatures of the given type + * {@code format}. + * + * @param format + * {@link GpgConfig.GpgFormat} the signer must support + * @return a {@link Signer}, or {@code null} if none is available + */ + public static Signer get(@NonNull GpgConfig.GpgFormat format) { + return SIGNERS.computeIfAbsent(format, f -> { + SignerFactory factory = SIGNER_FACTORIES.get(format); + if (factory == null) { + return null; + } + return factory.create(); + }); + } + + /** + * Sets a specific signer to use for a specific signature type. + * + * @param format + * signature type to set the {@code signer} for + * @param signer + * the {@link Signer} to use for signatures of type + * {@code format}; if {@code null}, a default implementation, if + * available, may be used. + */ + public static void set(@NonNull GpgConfig.GpgFormat format, Signer signer) { + if (signer == null) { + SIGNERS.remove(format); + } else { + SIGNERS.put(format, signer); + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java index bbc6144..ea73d95 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java
@@ -206,23 +206,6 @@ public void setTagger(PersonIdent taggerIdent) { return os.toByteArray(); } - /** - * Format this builder's state as an annotated tag object. - * - * @return this object in the canonical annotated tag format, suitable for - * storage in a repository, or {@code null} if the tag cannot be - * encoded - * @deprecated since 5.11; use {@link #build()} instead - */ - @Deprecated - public byte[] toByteArray() { - try { - return build(); - } catch (UnsupportedEncodingException e) { - return null; - } - } - @SuppressWarnings("nls") @Override public String toString() {
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 0c03adc..3d4e0d1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java
@@ -17,6 +17,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.util.FS; @@ -50,11 +51,36 @@ public interface TypedConfigGetter { * default value to return if no value was present. * @return true if any value or defaultValue is true, false for missing or * explicit false + * @deprecated use + * {@link #getBoolean(Config, String, String, String, Boolean)} + * instead */ + @Deprecated boolean getBoolean(Config config, String section, String subsection, String name, boolean defaultValue); /** + * Get a boolean value from a git {@link Config}. + * + * @param config + * to get the value from + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param defaultValue + * default value to return if no value was present. + * @return true if any value or defaultValue is true, false for missing or + * explicit false + * @since 7.2 + */ + @Nullable + Boolean getBoolean(Config config, String section, String subsection, + String name, @Nullable Boolean defaultValue); + + /** * Parse an enumeration from a git {@link Config}. * * @param <T> @@ -74,8 +100,9 @@ boolean getBoolean(Config config, String section, String subsection, * default value to return if no value was present. * @return the selected enumeration value, or {@code defaultValue}. */ + @Nullable <T extends Enum<?>> T getEnum(Config config, T[] all, String section, - String subsection, String name, T defaultValue); + String subsection, String name, @Nullable T defaultValue); /** * Obtain an integer value from a git {@link Config}. @@ -91,11 +118,34 @@ <T extends Enum<?>> T getEnum(Config config, T[] all, String section, * @param defaultValue * default value to return if no value was present. * @return an integer value from the configuration, or defaultValue. + * @deprecated use {@link #getInt(Config, String, String, String, Integer)} + * instead */ + @Deprecated int getInt(Config config, String section, String subsection, String name, int defaultValue); /** + * Obtain an integer value from a git {@link Config}. + * + * @param config + * to get the value from + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param defaultValue + * default value to return if no value was present. + * @return an integer value from the configuration, or defaultValue. + * @since 7.2 + */ + @Nullable + Integer getInt(Config config, String section, String subsection, + String name, @Nullable Integer defaultValue); + + /** * Obtain an integer value from a git {@link Config} which must be in given * range. * @@ -117,11 +167,43 @@ int getInt(Config config, String section, String subsection, String name, * @return an integer value from the configuration, or defaultValue. * {@code #UNSET_INT} if unset. * @since 6.1 + * @deprecated use + * {@link #getIntInRange(Config, String, String, String, int, int, Integer)} + * instead */ + @Deprecated int getIntInRange(Config config, String section, String subsection, String name, int minValue, int maxValue, int defaultValue); /** + * Obtain an integer value from a git {@link Config} which must be in given + * range. + * + * @param config + * to get the value from + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param minValue + * minimal value + * @param maxValue + * maximum value + * @param defaultValue + * default value to return if no value was present. Use + * {@code #UNSET_INT} to set the default to unset. + * @return an integer value from the configuration, or defaultValue. + * {@code #UNSET_INT} if unset. + * @since 7.2 + */ + @Nullable + Integer getIntInRange(Config config, String section, String subsection, + String name, int minValue, int maxValue, + @Nullable Integer defaultValue); + + /** * Obtain a long value from a git {@link Config}. * * @param config @@ -135,11 +217,34 @@ int getIntInRange(Config config, String section, String subsection, * @param defaultValue * default value to return if no value was present. * @return a long value from the configuration, or defaultValue. + * @deprecated use {@link #getLong(Config, String, String, String, Long)} + * instead */ + @Deprecated long getLong(Config config, String section, String subsection, String name, long defaultValue); /** + * Obtain a long value from a git {@link Config}. + * + * @param config + * to get the value from + * @param section + * section the key is grouped within. + * @param subsection + * subsection name, such a remote or branch name. + * @param name + * name of the key to get. + * @param defaultValue + * default value to return if no value was present. + * @return a long value from the configuration, or defaultValue. + * @since 7.2 + */ + @Nullable + Long getLong(Config config, String section, String subsection, String name, + @Nullable Long defaultValue); + + /** * Parse a numerical time unit, such as "1 minute", from a git * {@link Config}. * @@ -159,11 +264,41 @@ long getLong(Config config, String section, String subsection, String name, * indication of the units. * @return the value, or {@code defaultValue} if not set, expressed in * {@code units}. + * @deprecated use + * {@link #getTimeUnit(Config, String, String, String, Long, TimeUnit)} + * instead */ + @Deprecated long getTimeUnit(Config config, String section, String subsection, String name, long defaultValue, TimeUnit wantUnit); /** + * Parse a numerical time unit, such as "1 minute", from a git + * {@link Config}. + * + * @param config + * to get the value 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 defaultValue + * default value to return if no value was present. + * @param wantUnit + * the units of {@code defaultValue} and the return value, as + * well as the units to assume if the value does not contain an + * indication of the units. + * @return the value, or {@code defaultValue} if not set, expressed in + * {@code units}. + * @since 7.2 + */ + @Nullable + Long getTimeUnit(Config config, String section, String subsection, + String name, @Nullable 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> @@ -189,9 +324,10 @@ long getTimeUnit(Config config, String section, String subsection, * @return the {@link Path}, or {@code defaultValue} if not set * @since 5.10 */ + @Nullable default Path getPath(Config config, String section, String subsection, String name, @NonNull FS fs, File resolveAgainst, - Path defaultValue) { + @Nullable Path defaultValue) { String value = config.getString(section, subsection, name); if (value == null) { return defaultValue;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ContentMergeStrategy.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ContentMergeStrategy.java index 6d56864..a835a1d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ContentMergeStrategy.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ContentMergeStrategy.java
@@ -23,5 +23,12 @@ public enum ContentMergeStrategy { OURS, /** Resolve the conflict hunk using the theirs version. */ - THEIRS -} \ No newline at end of file + THEIRS, + + /** + * Resolve the conflict hunk using a union of both ours and theirs versions. + * + * @since 6.10.1 + */ + UNION +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java index 5734a25..d0d4d36 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
@@ -120,6 +120,7 @@ public <S extends Sequence> MergeResult<S> merge( result.add(1, 0, 0, ConflictState.NO_CONFLICT); break; case THEIRS: + case UNION: result.add(2, 0, theirs.size(), ConflictState.NO_CONFLICT); break; @@ -148,6 +149,7 @@ public <S extends Sequence> MergeResult<S> merge( // we modified, they deleted switch (strategy) { case OURS: + case UNION: result.add(1, 0, ours.size(), ConflictState.NO_CONFLICT); break; case THEIRS: @@ -158,7 +160,7 @@ public <S extends Sequence> MergeResult<S> merge( result.add(1, 0, ours.size(), ConflictState.FIRST_CONFLICTING_RANGE); result.add(0, 0, base.size(), - ConflictState.BASE_CONFLICTING_RANGE); + ConflictState.BASE_CONFLICTING_RANGE); result.add(2, 0, 0, ConflictState.NEXT_CONFLICTING_RANGE); break; } @@ -333,6 +335,15 @@ public <S extends Sequence> MergeResult<S> merge( theirsEndB - commonSuffix, ConflictState.NO_CONFLICT); break; + case UNION: + result.add(1, oursBeginB + commonPrefix, + oursEndB - commonSuffix, + ConflictState.NO_CONFLICT); + + result.add(2, theirsBeginB + commonPrefix, + theirsEndB - commonSuffix, + ConflictState.NO_CONFLICT); + break; default: result.add(1, oursBeginB + commonPrefix, oursEndB - commonSuffix,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java index a35b30e..079db4a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeFormatter.java
@@ -22,37 +22,6 @@ * A class to convert merge results into a Git conformant textual presentation */ public class MergeFormatter { - /** - * Formats the results of a merge of {@link org.eclipse.jgit.diff.RawText} - * objects in a Git conformant way. This method also assumes that the - * {@link org.eclipse.jgit.diff.RawText} objects being merged are line - * oriented files which use LF as delimiter. This method will also use LF to - * separate chunks and conflict metadata, therefore it fits only to texts - * that are LF-separated lines. - * - * @param out - * the output stream where to write the textual presentation - * @param res - * the merge result which should be presented - * @param seqName - * When a conflict is reported each conflicting range will get a - * name. This name is following the "<<<<<<< - * " or ">>>>>>> " conflict markers. The - * names for the sequences are given in this list - * @param charsetName - * the name of the character set used when writing conflict - * metadata - * @throws java.io.IOException - * if an IO error occurred - * @deprecated Use - * {@link #formatMerge(OutputStream, MergeResult, List, Charset)} - * instead. - */ - @Deprecated - public void formatMerge(OutputStream out, MergeResult<RawText> res, - List<String> seqName, String charsetName) throws IOException { - formatMerge(out, res, seqName, Charset.forName(charsetName)); - } /** * Formats the results of a merge of {@link org.eclipse.jgit.diff.RawText} @@ -129,40 +98,6 @@ public void formatMergeDiff3(OutputStream out, * the name ranges from ours should get * @param theirsName * the name ranges from theirs should get - * @param charsetName - * the name of the character set used when writing conflict - * metadata - * @throws java.io.IOException - * if an IO error occurred - * @deprecated use - * {@link #formatMerge(OutputStream, MergeResult, String, String, String, Charset)} - * instead. - */ - @Deprecated - public void formatMerge(OutputStream out, MergeResult res, String baseName, - String oursName, String theirsName, String charsetName) throws IOException { - formatMerge(out, res, baseName, oursName, theirsName, - Charset.forName(charsetName)); - } - - /** - * Formats the results of a merge of exactly two - * {@link org.eclipse.jgit.diff.RawText} objects in a Git conformant way. - * This convenience method accepts the names for the three sequences (base - * and the two merged sequences) as explicit parameters and doesn't require - * the caller to specify a List - * - * @param out - * the {@link java.io.OutputStream} where to write the textual - * presentation - * @param res - * the merge result which should be presented - * @param baseName - * the name ranges from the base should get - * @param oursName - * the name ranges from ours should get - * @param theirsName - * the name ranges from theirs should get * @param charset * the character set used when writing conflict metadata * @throws java.io.IOException
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java index e0c083f..039d7d8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
@@ -92,24 +92,6 @@ public String format(List<Ref> refsToMerge, Ref target) { } /** - * Add section with conflicting paths to merge message. Lines are prefixed - * with a hash. - * - * @param message - * the original merge message - * @param conflictingPaths - * the paths with conflicts - * @return merge message with conflicting paths added - * @deprecated since 6.1; use - * {@link #formatWithConflicts(String, Iterable, char)} instead - */ - @Deprecated - public String formatWithConflicts(String message, - List<String> conflictingPaths) { - return formatWithConflicts(message, conflictingPaths, '#'); - } - - /** * Add section with conflicting paths to merge message. * * @param message
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java index 1162a61..f58ef4f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -18,10 +18,11 @@ import java.io.IOException; import java.text.MessageFormat; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.TimeZone; +import java.util.stream.Collectors; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -185,12 +186,15 @@ protected RevCommit getBaseCommit(RevCommit a, RevCommit b, int callDepth) if (mergeTrees(bcTree, currentBase.getTree(), nextBase.getTree(), true)) currentBase = createCommitForTree(resultTree, parents); - else + else { + String failedPaths = failingPathsMessage(); throw new NoMergeBaseException( NoMergeBaseException.MergeBaseFailureReason.CONFLICTS_DURING_MERGE_BASE_CALCULATION, MessageFormat.format( JGitText.get().mergeRecursiveConflictsWhenMergingCommonAncestors, - currentBase.getName(), nextBase.getName())); + currentBase.getName(), nextBase.getName(), + failedPaths)); + } } } finally { inCore = oldIncore; @@ -229,11 +233,23 @@ private RevCommit createCommitForTree(ObjectId tree, List<RevCommit> parents) private static PersonIdent mockAuthor(List<RevCommit> parents) { String name = RecursiveMerger.class.getSimpleName(); int time = 0; - for (RevCommit p : parents) + for (RevCommit p : parents) { time = Math.max(time, p.getCommitTime()); - return new PersonIdent( - name, name + "@JGit", //$NON-NLS-1$ - new Date((time + 1) * 1000L), - TimeZone.getTimeZone("GMT+0000")); //$NON-NLS-1$ + } + return new PersonIdent(name, name + "@JGit", //$NON-NLS-1$ + Instant.ofEpochSecond(time+1), ZoneOffset.UTC); + } + + private String failingPathsMessage() { + int max = 25; + String failedPaths = failingPaths.entrySet().stream().limit(max) + .map(entry -> entry.getKey() + ":" + entry.getValue()) //$NON-NLS-1$ + .collect(Collectors.joining("\n")); //$NON-NLS-1$ + + if (failingPaths.size() > max) { + failedPaths = String.format("%s\n... (%s failing paths omitted)", //$NON-NLS-1$ + failedPaths, Integer.valueOf(failingPaths.size() - max)); + } + return failedPaths; } }
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 1ad41be..dc96f65 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -41,6 +41,7 @@ import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.attributes.Attributes; +import org.eclipse.jgit.attributes.AttributesNodeProvider; import org.eclipse.jgit.diff.DiffAlgorithm; import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm; import org.eclipse.jgit.diff.RawText; @@ -837,6 +838,13 @@ public enum MergeFailureReason { @NonNull private ContentMergeStrategy contentStrategy = ContentMergeStrategy.CONFLICT; + /** + * The {@link AttributesNodeProvider} to use while merging trees. + * + * @since 6.10.1 + */ + protected AttributesNodeProvider attributesNodeProvider; + private static MergeAlgorithm getMergeAlgorithm(Config config) { SupportedAlgorithm diffAlg = config.getEnum( CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM, @@ -1273,6 +1281,13 @@ protected boolean processEntry(CanonicalTreeParser base, default: break; } + if (ignoreConflicts) { + // If the path is selected to be treated as binary via attributes, we do not perform + // content merge. When ignoreConflicts = true, we simply keep OURS to allow virtual commit + // to be built. + keep(ourDce); + return true; + } // add the conflicting path to merge result String currentPath = tw.getPathString(); MergeResult<RawText> result = new MergeResult<>( @@ -1312,8 +1327,12 @@ protected boolean processEntry(CanonicalTreeParser base, addToCheckout(currentPath, null, attributes); return true; } catch (BinaryBlobException e) { - // if the file is binary in either OURS, THEIRS or BASE - // here, we don't have an option to ignore conflicts + // The file is binary in either OURS, THEIRS or BASE + if (ignoreConflicts) { + // When ignoreConflicts = true, we simply keep OURS to allow virtual commit to be built. + keep(ourDce); + return true; + } } } switch (getContentMergeStrategy()) { @@ -1354,6 +1373,8 @@ protected boolean processEntry(CanonicalTreeParser base, } } } else { + // This is reachable if contentMerge() call above threw BinaryBlobException, so we don't + // need to check ignoreConflicts here, since it's already handled above. result.setContainsConflicts(true); addConflict(base, ours, theirs); unmergedPaths.add(currentPath); @@ -1489,11 +1510,26 @@ private MergeResult<RawText> contentMerge(CanonicalTreeParser base, : getRawText(ours.getEntryObjectId(), attributes[T_OURS]); RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(theirs.getEntryObjectId(), attributes[T_THEIRS]); - mergeAlgorithm.setContentMergeStrategy(strategy); + mergeAlgorithm.setContentMergeStrategy( + getAttributesContentMergeStrategy(attributes[T_OURS], + strategy)); return mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText, ourText, theirsText); } + private ContentMergeStrategy getAttributesContentMergeStrategy( + Attributes attributes, ContentMergeStrategy strategy) { + Attribute attr = attributes.get(Constants.ATTR_MERGE); + if (attr != null) { + String attrValue = attr.getValue(); + if (attrValue != null && attrValue + .equals(Constants.ATTR_BUILTIN_UNION_MERGE_DRIVER)) { + return ContentMergeStrategy.UNION; + } + } + return strategy; + } + private boolean isIndexDirty() { if (inCore) { return false; @@ -1824,6 +1860,18 @@ public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) { this.workingTreeIterator = workingTreeIterator; } + /** + * Sets the {@link AttributesNodeProvider} to be used by this merger. + * + * @param attributesNodeProvider + * the attributeNodeProvider to set + * @since 6.10.1 + */ + public void setAttributesNodeProvider( + AttributesNodeProvider attributesNodeProvider) { + this.attributesNodeProvider = attributesNodeProvider; + } + /** * The resolve conflict way of three way merging @@ -1868,6 +1916,9 @@ protected boolean mergeTrees(AbstractTreeIterator baseTree, WorkTreeUpdater.createWorkTreeUpdater(db, dircache); dircache = workTreeUpdater.getLockedDirCache(); tw = new NameConflictTreeWalk(db, reader); + if (attributesNodeProvider != null) { + tw.setAttributesNodeProvider(attributesNodeProvider); + } tw.addTree(baseTree); tw.setHead(tw.addTree(headTree));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java index 79ceb13..30512c1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java
@@ -199,7 +199,7 @@ private void addIfNotNull(FanoutBucket b, int cell, NoteBucket child) if (child == null) return; if (child instanceof InMemoryNoteBucket) - b.setBucket(cell, ((InMemoryNoteBucket) child).writeTree(inserter)); + b.setBucket(cell, child.writeTree(inserter)); else b.setBucket(cell, child.getTreeId()); }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java index a327095..23e09b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/PatchApplier.java
@@ -23,6 +23,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -33,12 +34,13 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.zip.InflaterInputStream; + import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.errors.FilterFailedException; -import org.eclipse.jgit.api.errors.PatchFormatException; import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.attributes.Attributes; import org.eclipse.jgit.attributes.FilterCommand; @@ -101,11 +103,12 @@ * @since 6.4 */ public class PatchApplier { - private static final byte[] NO_EOL = "\\ No newline at end of file" //$NON-NLS-1$ .getBytes(StandardCharsets.US_ASCII); - /** The tree before applying the patch. Only non-null for inCore operation. */ + /** + * The tree before applying the patch. Only non-null for inCore operation. + */ @Nullable private final RevTree beforeTree; @@ -115,10 +118,14 @@ public class PatchApplier { private final ObjectReader reader; + private final Charset charset; + private WorkingTreeOptions workingTreeOptions; private int inCoreSizeLimit; + private boolean allowConflicts; + /** * @param repo * repository to apply the patch in @@ -128,7 +135,8 @@ public PatchApplier(Repository repo) { inserter = repo.newObjectInserter(); reader = inserter.newReader(); beforeTree = null; - + allowConflicts = false; + charset = StandardCharsets.UTF_8; Config config = repo.getConfig(); workingTreeOptions = config.get(WorkingTreeOptions.KEY); inCoreSizeLimit = config.getInt(ConfigConstants.CONFIG_MERGE_SECTION, @@ -143,11 +151,14 @@ public PatchApplier(Repository repo) { * @param oi * to be used for modifying objects */ - public PatchApplier(Repository repo, RevTree beforeTree, ObjectInserter oi) { + public PatchApplier(Repository repo, RevTree beforeTree, + ObjectInserter oi) { this.repo = repo; this.beforeTree = beforeTree; inserter = oi; reader = oi.newReader(); + allowConflicts = false; + charset = StandardCharsets.UTF_8; } /** @@ -157,7 +168,6 @@ public PatchApplier(Repository repo, RevTree beforeTree, ObjectInserter oi) { * @since 6.3 */ public static class Result { - /** * A wrapper for a patch applying error that affects a given file. * @@ -166,28 +176,68 @@ public static class Result { // TODO(ms): rename this class in next major release @SuppressWarnings("JavaLangClash") public static class Error { + final String msg; - private String msg; - private String oldFileName; - private @Nullable HunkHeader hh; + final String oldFileName; - private Error(String msg, String oldFileName, - @Nullable HunkHeader hh) { + @Nullable + final HunkHeader hh; + + final boolean isGitConflict; + + Error(String msg, String oldFileName, @Nullable HunkHeader hh, + boolean isGitConflict) { this.msg = msg; this.oldFileName = oldFileName; this.hh = hh; + this.isGitConflict = isGitConflict; + } + + /** + * Signals if as part of encountering this error, conflict markers + * were added to the file. + * + * @return {@code true} if conflict markers were added for this + * error. + * + * @since 6.10 + */ + public boolean isGitConflict() { + return isGitConflict; } @Override public String toString() { if (hh != null) { - return MessageFormat.format(JGitText.get().patchApplyErrorWithHunk, - oldFileName, hh, msg); + return MessageFormat.format( + JGitText.get().patchApplyErrorWithHunk, oldFileName, + hh, msg); } - return MessageFormat.format(JGitText.get().patchApplyErrorWithoutHunk, - oldFileName, msg); + return MessageFormat.format( + JGitText.get().patchApplyErrorWithoutHunk, oldFileName, + msg); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || !(o instanceof Error)) { + return false; + } + Error error = (Error) o; + return Objects.equals(msg, error.msg) + && Objects.equals(oldFileName, error.oldFileName) + && Objects.equals(hh, error.hh) + && isGitConflict == error.isGitConflict; + } + + @Override + public int hashCode() { + return Objects.hash(msg, oldFileName, hh, + Boolean.valueOf(isGitConflict)); + } } private ObjectId treeId; @@ -225,35 +275,15 @@ public List<Error> getErrors() { return errors; } - private void addError(String msg,String oldFileName, @Nullable HunkHeader hh) { - errors.add(new Error(msg, oldFileName, hh)); + private void addError(String msg, String oldFileName, + @Nullable HunkHeader hh) { + errors.add(new Error(msg, oldFileName, hh, false)); } - } - /** - * Applies the given patch - * - * @param patchInput - * the patch to apply. - * @return the result of the patch - * @throws PatchFormatException - * if the patch cannot be parsed - * @throws IOException - * if the patch read fails - * @deprecated use {@link #applyPatch(Patch)} instead - */ - @Deprecated - public Result applyPatch(InputStream patchInput) - throws PatchFormatException, IOException { - Patch p = new Patch(); - try (InputStream inStream = patchInput) { - p.parse(inStream); - - if (!p.getErrors().isEmpty()) { - throw new PatchFormatException(p.getErrors()); - } + private void addErrorWithGitConflict(String msg, String oldFileName, + @Nullable HunkHeader hh) { + errors.add(new Error(msg, oldFileName, hh, true)); } - return applyPatch(p); } /** @@ -357,6 +387,17 @@ else if (!dirCacheBuilder.commit()) { return result; } + /** + * Sets up the {@link PatchApplier} to apply patches even if they conflict. + * + * @return the {@link PatchApplier} to apply any patches + * @since 6.10 + */ + public PatchApplier allowConflicts() { + allowConflicts = true; + return this; + } + private File getFile(String path) { return inCore() ? null : new File(repo.getWorkTree(), path); } @@ -439,6 +480,7 @@ private boolean validGitPath(String path) { return false; } } + private static final int FILE_TREE_INDEX = 1; /** @@ -539,7 +581,9 @@ private void apply(String pathWithOriginalContent, DirCache dirCache, convertCrLf); resultStreamLoader = applyText(raw, fh, result); } - if (resultStreamLoader == null || !result.getErrors().isEmpty()) { + if (resultStreamLoader == null + || (!result.getErrors().isEmpty() && result.getErrors().stream() + .anyMatch(e -> !e.msg.equals("cannot apply hunk")))) { //$NON-NLS-1$ return; } @@ -961,9 +1005,51 @@ && canApplyAt(hunkLines, newLines, 0)) { } } if (!applies) { - result.addError(JGitText.get().applyTextPatchCannotApplyHunk, - fh.getOldPath(), hh); - return null; + if (!allowConflicts) { + result.addError( + JGitText.get().applyTextPatchCannotApplyHunk, + fh.getOldPath(), hh); + return null; + } + // Insert conflict markers. This is best-guess because the + // file might have changed completely. But at least we give + // the user a graceful state that they can resolve manually. + // An alternative to this is using the 3-way merger. This + // only works if the pre-image SHA is contained in the repo. + // If that was the case, cherry-picking the original commit + // should be preferred to apply a patch. + result.addErrorWithGitConflict("cannot apply hunk", fh.getOldPath(), hh); //$NON-NLS-1$ + newLines.add(Math.min(applyAt++, newLines.size()), + asBytes("<<<<<<< HEAD")); //$NON-NLS-1$ + applyAt += hh.getOldImage().lineCount; + newLines.add(Math.min(applyAt++, newLines.size()), + asBytes("=======")); //$NON-NLS-1$ + + int sz = hunkLines.size(); + for (int j = 1; j < sz; j++) { + ByteBuffer hunkLine = hunkLines.get(j); + if (!hunkLine.hasRemaining()) { + // Completely empty line; accept as empty context + // line + applyAt++; + lastWasRemoval = false; + continue; + } + switch (hunkLine.array()[hunkLine.position()]) { + case ' ': + case '+': + newLines.add(Math.min(applyAt++, newLines.size()), + slice(hunkLine, 1)); + break; + case '-': + case '\\': + default: + break; + } + } + newLines.add(Math.min(applyAt++, newLines.size()), + asBytes(">>>>>>> PATCH")); //$NON-NLS-1$ + continue; } // Hunk applies at applyAt. Apply it, and update afterLastHunk and // lineNumberShift @@ -1010,7 +1096,11 @@ && canApplyAt(hunkLines, newLines, 0)) { } else if (!rt.isMissingNewlineAtEnd()) { newLines.add(null); } + return toContentStreamLoader(newLines); + } + private static ContentStreamLoader toContentStreamLoader( + List<ByteBuffer> newLines) throws IOException { // We could check if old == new, but the short-circuiting complicates // logic for inCore patching, so just write the new thing regardless. TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(null); @@ -1034,6 +1124,10 @@ && canApplyAt(hunkLines, newLines, 0)) { } } + private ByteBuffer asBytes(String str) { + return ByteBuffer.wrap(str.getBytes(charset)); + } + @SuppressWarnings("ByteBufferBackingArray") private boolean canApplyAt(List<ByteBuffer> hunkLines, List<ByteBuffer> newLines, int line) { @@ -1123,4 +1217,4 @@ public void close() throws IOException { in.close(); } } -} +} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java index 82671d9..7c763bc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java
@@ -43,7 +43,7 @@ * Tree and blob objects reachable from interesting commits are automatically * scheduled for inclusion in the results of {@link #nextObject()}, returning * each object exactly once. Objects are sorted and returned according to the - * the commits that reference them and the order they appear within a tree. + * commits that reference them and the order they appear within a tree. * Ordering can be affected by changing the * {@link org.eclipse.jgit.revwalk.RevSort} used to order the commits that are * returned first. @@ -164,29 +164,6 @@ private ObjectWalk(ObjectReader or, boolean closeReader) { } /** - * Create an object reachability checker that will use bitmaps if possible. - * - * This reachability checker accepts any object as target. For checks - * exclusively between commits, see - * {@link RevWalk#createReachabilityChecker()}. - * - * @return an object reachability checker, using bitmaps if possible. - * - * @throws IOException - * when the index fails to load. - * - * @since 5.8 - * @deprecated use - * {@code ObjectReader#createObjectReachabilityChecker(ObjectWalk)} - * instead. - */ - @Deprecated - public final ObjectReachabilityChecker createObjectReachabilityChecker() - throws IOException { - return reader.createObjectReachabilityChecker(this); - } - - /** * Mark an object or commit to start graph traversal from. * <p> * Callers are encouraged to use
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java index 1a869a0..5afb669 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java
@@ -26,40 +26,6 @@ * @since 5.4 */ public interface ReachabilityChecker { - - /** - * Check if all targets are reachable from the {@code starters} commits. - * <p> - * Caller should parse the objectIds (preferably with - * {@code walk.parseCommit()} and handle missing/incorrect type objects - * before calling this method. - * - * @param targets - * commits to reach. - * @param starters - * known starting points. - * @return An unreachable target if at least one of the targets is - * unreachable. An empty optional if all targets are reachable from - * the starters. - * - * @throws MissingObjectException - * if any of the incoming objects doesn't exist in the - * repository. - * @throws IncorrectObjectTypeException - * if any of the incoming objects is not a commit or a tag. - * @throws IOException - * if any of the underlying indexes or readers can not be - * opened. - * - * @deprecated see {{@link #areAllReachable(Collection, Stream)} - */ - @Deprecated - default Optional<RevCommit> areAllReachable(Collection<RevCommit> targets, - Collection<RevCommit> starters) throws MissingObjectException, - IncorrectObjectTypeException, IOException { - return areAllReachable(targets, starters.stream()); - } - /** * Check if all targets are reachable from the {@code starters} commits. * <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java index 743a8cc..871545f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.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, 2024 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 @@ -401,13 +401,13 @@ public RevCommit getParent(int nth) { * @since 5.1 */ public final byte[] getRawGpgSignature() { - final byte[] raw = buffer; - final byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' }; - final int start = RawParseUtils.headerStart(header, raw, 0); + byte[] raw = buffer; + byte[] header = { 'g', 'p', 'g', 's', 'i', 'g' }; + int start = RawParseUtils.headerStart(header, raw, 0); if (start < 0) { return null; } - final int end = RawParseUtils.headerEnd(raw, start); + int end = RawParseUtils.nextLfSkippingSplitLines(raw, start); return RawParseUtils.headerValue(raw, start, end); } @@ -524,6 +524,30 @@ static boolean hasLF(byte[] r, int b, int e) { } /** + * Parse the commit message and return its first line, i.e., everything up + * to but not including the first newline, if any. + * + * @return the first line of the decoded commit message as a string; never + * {@code null}. + * @since 7.2 + */ + public final String getFirstMessageLine() { + int msgB = RawParseUtils.commitMessage(buffer, 0); + if (msgB < 0) { + return ""; //$NON-NLS-1$ + } + int msgE = msgB; + byte[] raw = buffer; + while (msgE < raw.length && raw[msgE] != '\n') { + msgE++; + } + if (msgE > msgB && msgE > 0 && raw[msgE - 1] == '\r') { + msgE--; + } + return RawParseUtils.decode(guessEncoding(buffer), buffer, msgB, msgE); + } + + /** * Determine the encoding of the commit message buffer. * <p> * Locates the "encoding" header (if present) and returns its value. Due to
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java index 75dbd57..0737a78 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
@@ -38,8 +38,17 @@ */ public class RevTag extends RevObject { - private static final byte[] hSignature = Constants - .encodeASCII("-----BEGIN PGP SIGNATURE-----"); //$NON-NLS-1$ + private static final byte[] SIGNATURE_START = Constants + .encodeASCII("-----BEGIN"); //$NON-NLS-1$ + + private static final byte[] GPG_SIGNATURE_START = Constants + .encodeASCII(Constants.GPG_SIGNATURE_PREFIX); + + private static final byte[] CMS_SIGNATURE_START = Constants + .encodeASCII(Constants.CMS_SIGNATURE_PREFIX); + + private static final byte[] SSH_SIGNATURE_START = Constants + .encodeASCII(Constants.SSH_SIGNATURE_PREFIX); /** * Parse an annotated tag from its canonical format. @@ -208,20 +217,27 @@ private int getSignatureStart() { return msgB; } // Find the last signature start and return the rest - int start = nextStart(hSignature, raw, msgB); + int start = nextStart(SIGNATURE_START, raw, msgB); if (start < 0) { return start; } int next = RawParseUtils.nextLF(raw, start); while (next < raw.length) { - int newStart = nextStart(hSignature, raw, next); + int newStart = nextStart(SIGNATURE_START, raw, next); if (newStart < 0) { break; } start = newStart; next = RawParseUtils.nextLF(raw, start); } - return start; + // SIGNATURE_START is just a prefix. Check that it is one of the known + // full signature start tags. + if (RawParseUtils.match(raw, start, GPG_SIGNATURE_START) > 0 + || RawParseUtils.match(raw, start, CMS_SIGNATURE_START) > 0 + || RawParseUtils.match(raw, start, SSH_SIGNATURE_START) > 0) { + return start; + } + return -1; } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java index 76c14e9..41f98ba 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -19,9 +19,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Optional; +import java.util.Map; +import java.util. +Optional; +import java.util.Set; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; @@ -31,9 +36,9 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.RevWalkException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AsyncObjectLoaderQueue; -import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.NullProgressMonitor; @@ -279,23 +284,6 @@ public ObjectReader getObjectReader() { } /** - * Get a reachability checker for commits over this revwalk. - * - * @return the most efficient reachability checker for this repository. - * @throws IOException - * if it cannot open any of the underlying indices. - * - * @since 5.4 - * @deprecated use {@code ObjectReader#createReachabilityChecker(RevWalk)} - * instead. - */ - @Deprecated - public final ReachabilityChecker createReachabilityChecker() - throws IOException { - return reader.createReachabilityChecker(this); - } - - /** * {@inheritDoc} * <p> * Release any resources used by this walker's reader. @@ -540,6 +528,27 @@ public boolean isMergedIntoAny(RevCommit commit, Collection<Ref> refs) } /** + * Determine if a <code>commit</code> is merged into any of the given + * <code>revs</code>. + * + * @param commit + * commit the caller thinks is reachable from <code>revs</code>. + * @param revs + * commits to start iteration from, and which is most likely a + * descendant (child) of <code>commit</code>. + * @return true if commit is merged into any of the revs; false otherwise. + * @throws java.io.IOException + * a pack file or loose object could not be read. + * @since 6.10.1 + */ + public boolean isMergedIntoAnyCommit(RevCommit commit, Collection<RevCommit> revs) + throws IOException { + return getCommitsMergedInto(commit, revs, + GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND, + NullProgressMonitor.INSTANCE).size() > 0; + } + + /** * Determine if a <code>commit</code> is merged into all of the given * <code>refs</code>. * @@ -562,7 +571,26 @@ public boolean isMergedIntoAll(RevCommit commit, Collection<Ref> refs) private List<Ref> getMergedInto(RevCommit needle, Collection<Ref> haystacks, Enum returnStrategy, ProgressMonitor monitor) throws IOException { + Map<RevCommit, List<Ref>> refsByCommit = new HashMap<>(); + for (Ref r : haystacks) { + RevObject o = peel(parseAny(r.getObjectId())); + if (!(o instanceof RevCommit)) { + continue; + } + refsByCommit.computeIfAbsent((RevCommit) o, c -> new ArrayList<>()).add(r); + } + monitor.update(1); List<Ref> result = new ArrayList<>(); + for (RevCommit c : getCommitsMergedInto(needle, refsByCommit.keySet(), + returnStrategy, monitor)) { + result.addAll(refsByCommit.get(c)); + } + return result; + } + + private Set<RevCommit> getCommitsMergedInto(RevCommit needle, Collection<RevCommit> haystacks, + Enum returnStrategy, ProgressMonitor monitor) throws IOException { + Set<RevCommit> result = new HashSet<>(); List<RevCommit> uninteresting = new ArrayList<>(); List<RevCommit> marked = new ArrayList<>(); RevFilter oldRF = filter; @@ -578,16 +606,11 @@ private List<Ref> getMergedInto(RevCommit needle, Collection<Ref> haystacks, needle.parseHeaders(this); } int cutoff = needle.getGeneration(); - for (Ref r : haystacks) { + for (RevCommit c : haystacks) { if (monitor.isCancelled()) { return result; } monitor.update(1); - RevObject o = peel(parseAny(r.getObjectId())); - if (!(o instanceof RevCommit)) { - continue; - } - RevCommit c = (RevCommit) o; reset(UNINTERESTING | TEMP_MARK); markStart(c); boolean commitFound = false; @@ -599,7 +622,7 @@ private List<Ref> getMergedInto(RevCommit needle, Collection<Ref> haystacks, } if (References.isSameObject(next, needle) || (next.flags & TEMP_MARK) != 0) { - result.add(r); + result.add(c); if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_FOUND) { return result; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java index 4100e87..c9186b5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/filter/CommitTimeRevFilter.java
@@ -12,6 +12,7 @@ package org.eclipse.jgit.revwalk.filter; import java.io.IOException; +import java.time.Instant; import java.util.Date; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -30,9 +31,24 @@ public abstract class CommitTimeRevFilter extends RevFilter { * @param ts * the point in time to cut on. * @return a new filter to select commits on or before <code>ts</code>. + * + * @deprecated Use {@link #before(Instant)} instead. */ + @Deprecated(since="7.2") public static final RevFilter before(Date ts) { - return before(ts.getTime()); + return before(ts.toInstant()); + } + + /** + * Create a new filter to select commits before a given date/time. + * + * @param ts + * the point in time to cut on. + * @return a new filter to select commits on or before <code>ts</code>. + * @since 7.2 + */ + public static RevFilter before(Instant ts) { + return new Before(ts); } /** @@ -43,7 +59,7 @@ public static final RevFilter before(Date ts) { * @return a new filter to select commits on or before <code>ts</code>. */ public static final RevFilter before(long ts) { - return new Before(ts); + return new Before(Instant.ofEpochMilli(ts)); } /** @@ -52,9 +68,24 @@ public static final RevFilter before(long ts) { * @param ts * the point in time to cut on. * @return a new filter to select commits on or after <code>ts</code>. + * + * @deprecated Use {@link #after(Instant)} instead. */ + @Deprecated(since="7.2") public static final RevFilter after(Date ts) { - return after(ts.getTime()); + return after(ts.toInstant()); + } + + /** + * Create a new filter to select commits after a given date/time. + * + * @param ts + * the point in time to cut on. + * @return a new filter to select commits on or after <code>ts</code>. + * @since 7.2 + */ + public static RevFilter after(Instant ts) { + return new After(ts); } /** @@ -65,7 +96,7 @@ public static final RevFilter after(Date ts) { * @return a new filter to select commits on or after <code>ts</code>. */ public static final RevFilter after(long ts) { - return new After(ts); + return after(Instant.ofEpochMilli(ts)); } /** @@ -75,9 +106,28 @@ public static final RevFilter after(long ts) { * @param since the point in time to cut on. * @param until the point in time to cut off. * @return a new filter to select commits between the given date/times. + * + * @deprecated Use {@link #between(Instant, Instant)} instead. */ + @Deprecated(since="7.2") public static final RevFilter between(Date since, Date until) { - return between(since.getTime(), until.getTime()); + return between(since.toInstant(), until.toInstant()); + } + + /** + * Create a new filter to select commits after or equal a given date/time + * <code>since</code> and before or equal a given date/time + * <code>until</code>. + * + * @param since + * the point in time to cut on. + * @param until + * the point in time to cut off. + * @return a new filter to select commits between the given date/times. + * @since 7.2 + */ + public static RevFilter between(Instant since, Instant until) { + return new Between(since, until); } /** @@ -87,9 +137,12 @@ public static final RevFilter between(Date since, Date until) { * @param since the point in time to cut on, in milliseconds. * @param until the point in time to cut off, in millisconds. * @return a new filter to select commits between the given date/times. + * + * @deprecated Use {@link #between(Instant, Instant)} instead. */ + @Deprecated(since="7.2") public static final RevFilter between(long since, long until) { - return new Between(since, until); + return new Between(Instant.ofEpochMilli(since), Instant.ofEpochMilli(until)); } final int when; @@ -98,6 +151,10 @@ public static final RevFilter between(long since, long until) { when = (int) (ts / 1000); } + CommitTimeRevFilter(Instant t) { + when = (int) t.getEpochSecond(); + } + @Override public RevFilter clone() { return this; @@ -109,8 +166,8 @@ public boolean requiresCommitBody() { } private static class Before extends CommitTimeRevFilter { - Before(long ts) { - super(ts); + Before(Instant t) { + super(t); } @Override @@ -123,14 +180,12 @@ public boolean include(RevWalk walker, RevCommit cmit) @SuppressWarnings("nls") @Override public String toString() { - return super.toString() + "(" + new Date(when * 1000L) + ")"; + return super.toString() + "(" + Instant.ofEpochSecond(when) + ")"; } } private static class After extends CommitTimeRevFilter { - After(long ts) { - super(ts); - } + After(Instant t) { super(t); } @Override public boolean include(RevWalk walker, RevCommit cmit) @@ -148,16 +203,16 @@ public boolean include(RevWalk walker, RevCommit cmit) @SuppressWarnings("nls") @Override public String toString() { - return super.toString() + "(" + new Date(when * 1000L) + ")"; + return super.toString() + "(" + Instant.ofEpochSecond(when) + ")"; } } private static class Between extends CommitTimeRevFilter { private final int until; - Between(long since, long until) { + Between(Instant since, Instant until) { super(since); - this.until = (int) (until / 1000); + this.until = (int) until.getEpochSecond(); } @Override @@ -170,8 +225,8 @@ public boolean include(RevWalk walker, RevCommit cmit) @SuppressWarnings("nls") @Override public String toString() { - return super.toString() + "(" + new Date(when * 1000L) + " - " - + new Date(until * 1000L) + ")"; + return super.toString() + "(" + Instant.ofEpochSecond(when) + " - " + + Instant.ofEpochSecond(until) + ")"; } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java index 7cb8618..668b92c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/WindowCacheStats.java
@@ -22,27 +22,6 @@ */ @MXBean public interface WindowCacheStats { - /** - * Get number of open files - * - * @return the number of open files. - * @deprecated use {@link #getOpenFileCount()} instead - */ - @Deprecated - public static int getOpenFiles() { - return (int) WindowCache.getInstance().getStats().getOpenFileCount(); - } - - /** - * Get number of open bytes - * - * @return the number of open bytes. - * @deprecated use {@link #getOpenByteCount()} instead - */ - @Deprecated - public static long getOpenBytes() { - return WindowCache.getInstance().getStats().getOpenByteCount(); - } /** * Get cache statistics
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java index 8373d68..863b794 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
@@ -50,7 +50,7 @@ import java.util.concurrent.TimeUnit; import java.util.zip.Deflater; -import org.eclipse.jgit.internal.storage.file.PackIndexWriter; +import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Repository; @@ -995,7 +995,7 @@ public void setExecutor(Executor executor) { * * @return the index version, the special version 0 designates the oldest * (most compatible) format available for the objects. - * @see PackIndexWriter + * @see BasePackIndexWriter */ public int getIndexVersion() { return indexVersion; @@ -1009,7 +1009,7 @@ public int getIndexVersion() { * @param version * the version to write. The special version 0 designates the * oldest (most compatible) format available for the objects. - * @see PackIndexWriter + * @see BasePackIndexWriter */ public void setIndexVersion(int version) { indexVersion = version;
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 becc808..105cba7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -787,14 +787,14 @@ public IgnoreSubmoduleMode getModulesIgnore() throws IOException, IgnoreSubmoduleMode mode = repoConfig.getEnum( IgnoreSubmoduleMode.values(), ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(), - ConfigConstants.CONFIG_KEY_IGNORE, null); + ConfigConstants.CONFIG_KEY_IGNORE); if (mode != null) { return mode; } lazyLoadModulesConfig(); - return modulesConfig.getEnum(IgnoreSubmoduleMode.values(), - ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(), - ConfigConstants.CONFIG_KEY_IGNORE, IgnoreSubmoduleMode.NONE); + return modulesConfig.getEnum(ConfigConstants.CONFIG_SUBMODULE_SECTION, + getModuleName(), ConfigConstants.CONFIG_KEY_IGNORE, + IgnoreSubmoduleMode.NONE); } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java index b873925..aaf9f8a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
@@ -757,8 +757,10 @@ void list() throws IOException { final XMLReader xr; try { - xr = SAXParserFactory.newInstance().newSAXParser() - .getXMLReader(); + SAXParserFactory saxParserFactory = SAXParserFactory + .newInstance(); + saxParserFactory.setNamespaceAware(true); + xr = saxParserFactory.newSAXParser().getXMLReader(); } catch (SAXException | ParserConfigurationException e) { throw new IOException( JGitText.get().noXMLParserAvailable, e);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java index 469a3d6..be0d37b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -12,10 +12,10 @@ package org.eclipse.jgit.transport; -import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DELIM; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN_NOT; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN_SINCE; +import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DELIM; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DONE; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_END; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_ERR; @@ -32,7 +32,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -715,7 +714,7 @@ private void markReachable(Collection<Ref> want, Set<ObjectId> have, // wind up later matching up against things we want and we // can avoid asking for something we already happen to have. // - final Date maxWhen = new Date(maxTime * 1000L); + Instant maxWhen = Instant.ofEpochSecond(maxTime); walk.sort(RevSort.COMMIT_TIME_DESC); walk.markStart(reachableCommits); walk.setRevFilter(CommitTimeRevFilter.after(maxWhen));
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 73eddb8..f10b7bf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java
@@ -302,8 +302,7 @@ private void init(Config config, URIish uri) { int postBufferSize = config.getInt(HTTP, POST_BUFFER_KEY, 1 * 1024 * 1024); boolean sslVerifyFlag = config.getBoolean(HTTP, SSL_VERIFY_KEY, true); - HttpRedirectMode followRedirectsMode = config.getEnum( - HttpRedirectMode.values(), HTTP, null, + HttpRedirectMode followRedirectsMode = config.getEnum(HTTP, null, FOLLOW_REDIRECTS_KEY, HttpRedirectMode.INITIAL); int redirectLimit = config.getInt(HTTP, MAX_REDIRECTS_KEY, MAX_REDIRECTS); @@ -335,8 +334,8 @@ private void init(Config config, URIish uri) { postBufferSize); sslVerifyFlag = config.getBoolean(HTTP, match, SSL_VERIFY_KEY, sslVerifyFlag); - followRedirectsMode = config.getEnum(HttpRedirectMode.values(), - HTTP, match, FOLLOW_REDIRECTS_KEY, followRedirectsMode); + followRedirectsMode = config.getEnum(HTTP, match, + FOLLOW_REDIRECTS_KEY, followRedirectsMode); int newMaxRedirects = config.getInt(HTTP, match, MAX_REDIRECTS_KEY, redirectLimit); if (newMaxRedirects >= 0) {
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 7224405..e1f2b19 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -530,7 +530,7 @@ public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving) receiving.beginTask(JGitText.get().receivingObjects, (int) expectedObjectCount); try { - for (int done = 0; done < expectedObjectCount; done++) { + for (long done = 0; done < expectedObjectCount; done++) { indexOneObject(); receiving.update(1); if (receiving.isCancelled())
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 ed33eae..614ad88 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
@@ -43,24 +43,13 @@ public class PacketLineIn { /** * Magic return from {@link #readString()} when a flush packet is found. - * - * @deprecated Callers should use {@link #isEnd(String)} to check if a - * string is the end marker, or - * {@link PacketLineIn#readStrings()} to iterate over all - * strings in the input stream until the marker is reached. */ - @Deprecated - public static final String END = new String(); /* must not string pool */ + private static final String END = new String(); /* must not string pool */ /** * Magic return from {@link #readString()} when a delim packet is found. - * - * @since 5.0 - * @deprecated Callers should use {@link #isDelimiter(String)} to check if a - * string is the delimiter. */ - @Deprecated - public static final String DELIM = new String(); /* must not string pool */ + private static final String DELIM = new String(); /* must not string pool */ enum AckNackResult { /** NAK */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java index a9e93b6..6bdaf0e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
@@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -329,7 +330,7 @@ public RefUpdate.Result save() throws IOException { if (newId == null) { return RefUpdate.Result.NO_CHANGE; } - try (ObjectInserter inserter = db.newObjectInserter()) { + try { RefUpdate.Result result = updateRef(newId); switch (result) { case FAST_FORWARD: @@ -404,8 +405,8 @@ private ObjectId write() throws IOException { } private static void sortPending(List<PendingCert> pending) { - Collections.sort(pending, (PendingCert a, PendingCert b) -> Long.signum( - a.ident.getWhen().getTime() - b.ident.getWhen().getTime())); + Collections.sort(pending, + Comparator.comparing((PendingCert a) -> a.ident.getWhenAsInstant())); } private DirCache newDirCache() throws IOException { @@ -503,7 +504,7 @@ private static String buildMessage(PushCertificate cert) { } else { sb.append(MessageFormat.format( JGitText.get().storePushCertMultipleRefs, - Integer.valueOf(cert.getCommands().size()))); + cert.getCommands().size())); } return sb.append('\n').toString(); }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index ddde603..6f211e0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -88,52 +88,6 @@ * Implements the server side of a push connection, receiving objects. */ public class ReceivePack { - /** - * Data in the first line of a request, the line itself plus capabilities. - * - * @deprecated Use {@link FirstCommand} instead. - * @since 5.6 - */ - @Deprecated - public static class FirstLine { - private final FirstCommand command; - - /** - * Parse the first line of a receive-pack request. - * - * @param line - * line from the client. - */ - public FirstLine(String line) { - command = FirstCommand.fromLine(line); - } - - /** - * Get non-capabilities part of the line - * - * @return non-capabilities part of the line. - */ - public String getLine() { - return command.getLine(); - } - - /** - * Get capabilities parsed from the line - * - * @return capabilities parsed from the line. - */ - public Set<String> getCapabilities() { - Set<String> reconstructedCapabilites = new HashSet<>(); - for (Map.Entry<String, String> e : command.getCapabilities() - .entrySet()) { - String cap = e.getValue() == null ? e.getKey() - : e.getKey() + "=" + e.getValue(); //$NON-NLS-1$ - reconstructedCapabilites.add(cap); - } - - return reconstructedCapabilites; - } - } /** Database we write the stored objects into. */ private final Repository db; @@ -2149,22 +2103,6 @@ public void setUnpackErrorHandler(UnpackErrorHandler unpackErrorHandler) { } /** - * Set whether this class will report command failures as warning messages - * before sending the command results. - * - * @param echo - * if true this class will report command failures as warning - * messages before sending the command results. This is usually - * not necessary, but may help buggy Git clients that discard the - * errors when all branches fail. - * @deprecated no widely used Git versions need this any more - */ - @Deprecated - public void setEchoCommandFailures(boolean echo) { - // No-op. - } - - /** * Get the client session-id * * @return The client session-id.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java index f72c421..3d4bea2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java
@@ -178,7 +178,6 @@ public void setUseProtocolV2(boolean b) { * * This method must be invoked prior to any of the following: * <ul> - * <li>{@link #send(Map)}</li> * <li>{@link #send(Collection)}</li> * </ul> * @@ -195,7 +194,6 @@ public void setDerefTags(boolean deref) { * <p> * This method must be invoked prior to any of the following: * <ul> - * <li>{@link #send(Map)}</li> * <li>{@link #send(Collection)}</li> * <li>{@link #advertiseHave(AnyObjectId)}</li> * </ul> @@ -230,7 +228,6 @@ public void advertiseCapability(String name, String value) { * <p> * This method must be invoked prior to any of the following: * <ul> - * <li>{@link #send(Map)}</li> * <li>{@link #send(Collection)}</li> * <li>{@link #advertiseHave(AnyObjectId)}</li> * </ul> @@ -260,24 +257,6 @@ public void addSymref(String from, String to) { * @throws java.io.IOException * the underlying output stream failed to write out an * advertisement record. - * @deprecated use {@link #send(Collection)} instead. - */ - @Deprecated - public Set<ObjectId> send(Map<String, Ref> refs) throws IOException { - return send(refs.values()); - } - - /** - * Format an advertisement for the supplied refs. - * - * @param refs - * zero or more refs to format for the client. The collection is - * sorted before display if necessary, and therefore may appear - * in any order. - * @return set of ObjectIds that were advertised to the client. - * @throws java.io.IOException - * the underlying output stream failed to write out an - * advertisement record. * @since 5.0 */ public Set<ObjectId> send(Collection<Ref> refs) throws IOException {
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 a0194ea..8120df0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
@@ -11,8 +11,6 @@ package org.eclipse.jgit.transport; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Iterator; import java.util.ServiceLoader; @@ -99,9 +97,8 @@ public static void setInstance(SshSessionFactory newFactory) { * @since 5.2 */ public static String getLocalUserName() { - return AccessController - .doPrivileged((PrivilegedAction<String>) () -> SystemReader - .getInstance().getProperty(Constants.OS_USER_NAME_KEY)); + return SystemReader.getInstance() + .getProperty(Constants.OS_USER_NAME_KEY); } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java index b335675..ac76e83 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -1121,28 +1121,6 @@ public void setRemoveDeletedRefs(boolean remove) { } /** - * @return the blob limit value set with {@link #setFilterBlobLimit} or - * {@link #setFilterSpec(FilterSpec)}, or -1 if no blob limit value - * was set - * @since 5.0 - * @deprecated Use {@link #getFilterSpec()} instead - */ - @Deprecated - public final long getFilterBlobLimit() { - return filterSpec.getBlobLimit(); - } - - /** - * @param bytes exclude blobs of size greater than this - * @since 5.0 - * @deprecated Use {@link #setFilterSpec(FilterSpec)} instead - */ - @Deprecated - public final void setFilterBlobLimit(long bytes) { - setFilterSpec(FilterSpec.withBlobLimit(bytes)); - } - - /** * Get filter spec * * @return the last filter spec set with {@link #setFilterSpec(FilterSpec)},
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java index 0fc9710..f77b041 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
@@ -254,6 +254,12 @@ private ProcessBuilder createProcess(List<String> args, pb.environment().put(Constants.GIT_DIR_KEY, directory.getPath()); } + File commonDirectory = local != null ? local.getCommonDirectory() + : null; + if (commonDirectory != null) { + pb.environment().put(Constants.GIT_COMMON_DIR_KEY, + commonDirectory.getPath()); + } return pb; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java index 3a06ce5..1b9431c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
@@ -225,6 +225,7 @@ private Process spawn(String cmd, env.remove("GIT_CONFIG"); //$NON-NLS-1$ env.remove("GIT_CONFIG_PARAMETERS"); //$NON-NLS-1$ env.remove("GIT_DIR"); //$NON-NLS-1$ + env.remove("GIT_COMMON_DIR"); //$NON-NLS-1$ env.remove("GIT_WORK_TREE"); //$NON-NLS-1$ env.remove("GIT_GRAFT_FILE"); //$NON-NLS-1$ env.remove("GIT_INDEX_FILE"); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java index 4de6ff8..7b5842b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
@@ -82,7 +82,7 @@ public class URIish implements Serializable { * Part of a pattern which matches a relative path. Relative paths don't * start with slash or drive letters. Defines no capturing group. */ - private static final String RELATIVE_PATH_P = "(?:(?:[^\\\\/]+[\\\\/]+)*[^\\\\/]+[\\\\/]*)"; //$NON-NLS-1$ + private static final String RELATIVE_PATH_P = "(?:(?:[^\\\\/]+[\\\\/]+)*+[^\\\\/]*)"; //$NON-NLS-1$ /** * Part of a pattern which matches a relative or absolute path. Defines no @@ -120,7 +120,7 @@ public class URIish implements Serializable { * path (maybe even containing windows drive-letters) or a relative path. */ private static final Pattern LOCAL_FILE = Pattern.compile("^" // //$NON-NLS-1$ - + "([\\\\/]?" + PATH_P + ")" // //$NON-NLS-1$ //$NON-NLS-2$ + + "([\\\\/]?+" + PATH_P + ")" // //$NON-NLS-1$ //$NON-NLS-2$ + "$"); //$NON-NLS-1$ /**
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 9318871..41ab8ac 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -30,11 +30,11 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_NO_DONE; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_NO_PROGRESS; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_OFS_DELTA; +import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SESSION_ID; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SHALLOW; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_ALL; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K; -import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SESSION_ID; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_WAIT_FOR_DONE; import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_ACK; @@ -80,7 +80,6 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.CachedPackUriProvider; import org.eclipse.jgit.internal.storage.pack.PackWriter; -import org.eclipse.jgit.internal.transport.parser.FirstWant; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; @@ -118,13 +117,13 @@ public class UploadPack implements Closeable { /** Policy the server uses to validate client requests */ public enum RequestPolicy { /** Client may only ask for objects the server advertised a reference for. */ - ADVERTISED, + ADVERTISED(0x08), /** * Client may ask for any commit reachable from a reference advertised by * the server. */ - REACHABLE_COMMIT, + REACHABLE_COMMIT(0x02), /** * Client may ask for objects that are the tip of any reference, even if not @@ -134,18 +133,36 @@ public enum RequestPolicy { * * @since 3.1 */ - TIP, + TIP(0x01), /** * Client may ask for any commit reachable from any reference, even if that - * reference wasn't advertised. + * reference wasn't advertised, implies REACHABLE_COMMIT and TIP. * * @since 3.1 */ - REACHABLE_COMMIT_TIP, + REACHABLE_COMMIT_TIP(0x03), - /** Client may ask for any SHA-1 in the repository. */ - ANY; + /** Client may ask for any SHA-1 in the repository, implies REACHABLE_COMMIT_TIP. */ + ANY(0x07); + + private final int bitmask; + + RequestPolicy(int bitmask) { + this.bitmask = bitmask; + } + + /** + * Check if the current policy implies another, based on its bitmask. + * + * @param implied + * the implied policy based on its bitmask. + * @return true if the policy is implied. + * @since 6.10.1 + */ + public boolean implies(RequestPolicy implied) { + return (bitmask & implied.bitmask) != 0; + } } /** @@ -172,52 +189,6 @@ void checkWants(UploadPack up, List<ObjectId> wants) throws PackProtocolException, IOException; } - /** - * Data in the first line of a want-list, the line itself plus options. - * - * @deprecated Use {@link FirstWant} instead - */ - @Deprecated - public static class FirstLine { - - private final FirstWant firstWant; - - /** - * @param line - * line from the client. - */ - public FirstLine(String line) { - try { - firstWant = FirstWant.fromLine(line); - } catch (PackProtocolException e) { - throw new UncheckedIOException(e); - } - } - - /** - * Get non-capabilities part of the line - * - * @return non-capabilities part of the line. - */ - public String getLine() { - return firstWant.getLine(); - } - - /** - * Get capabilities parsed from the line - * - * @return capabilities parsed from the line. - */ - public Set<String> getOptions() { - if (firstWant.getAgent() != null) { - Set<String> caps = new HashSet<>(firstWant.getCapabilities()); - caps.add(OPTION_AGENT + '=' + firstWant.getAgent()); - return caps; - } - return firstWant.getCapabilities(); - } - } - /* * {@link java.util.function.Consumer} doesn't allow throwing checked * exceptions. Define our own to propagate IOExceptions. @@ -1423,6 +1394,7 @@ private List<String> getV2CapabilityAdvertisement() { if (transferConfig.isAdvertiseObjectInfo()) { caps.add(COMMAND_OBJECT_INFO); } + caps.add(OPTION_AGENT + "=" + UserAgent.get()); return caps; } @@ -1629,13 +1601,9 @@ public void sendAdvertisedRefs(RefAdvertiser adv, if (!biDirectionalPipe) adv.advertiseCapability(OPTION_NO_DONE); RequestPolicy policy = getRequestPolicy(); - if (policy == RequestPolicy.TIP - || policy == RequestPolicy.REACHABLE_COMMIT_TIP - || policy == null) + if (policy == null || policy.implies(RequestPolicy.TIP)) adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT); - if (policy == RequestPolicy.REACHABLE_COMMIT - || policy == RequestPolicy.REACHABLE_COMMIT_TIP - || policy == null) + if (policy == null || policy.implies(RequestPolicy.REACHABLE_COMMIT)) adv.advertiseCapability(OPTION_ALLOW_REACHABLE_SHA1_IN_WANT); adv.advertiseCapability(OPTION_AGENT, UserAgent.get()); if (transferConfig.isAllowFilter()) { @@ -1693,18 +1661,6 @@ public int getDepth() { } /** - * Deprecated synonym for {@code getFilterSpec().getBlobLimit()}. - * - * @return filter blob limit requested by the client, or -1 if no limit - * @since 5.3 - * @deprecated Use {@link #getFilterSpec()} instead - */ - @Deprecated - public final long getFilterBlobLimit() { - return getFilterSpec().getBlobLimit(); - } - - /** * Returns the filter spec for the current request. Valid only after * calling recvWants(). This may be a no-op filter spec, but it won't be * null. @@ -1996,10 +1952,9 @@ public static final class AdvertisedRequestValidator @Override public void checkWants(UploadPack up, List<ObjectId> wants) throws PackProtocolException, IOException { - if (!up.isBiDirectionalPipe()) + if (!up.isBiDirectionalPipe() || !wants.isEmpty()) { new ReachableCommitRequestValidator().checkWants(up, wants); - else if (!wants.isEmpty()) - throw new WantNotValidException(wants.iterator().next()); + } } } @@ -2271,7 +2226,7 @@ private boolean wantSatisfied(RevObject want) throws IOException { walk.resetRetain(SAVE); walk.markStart((RevCommit) want); if (oldestTime != 0) - walk.setRevFilter(CommitTimeRevFilter.after(oldestTime * 1000L)); + walk.setRevFilter(CommitTimeRevFilter.after(Instant.ofEpochSecond(oldestTime))); for (;;) { final RevCommit c = walk.next(); if (c == null) @@ -2429,7 +2384,8 @@ else if (ref.getName().startsWith(Constants.R_HEADS)) : req.getDepth() - 1; pw.setShallowPack(req.getDepth(), unshallowCommits); - // Ownership is transferred below + // dw borrows the reader from walk which is closed by #close + @SuppressWarnings("resource") DepthWalk.RevWalk dw = new DepthWalk.RevWalk( walk.getObjectReader(), walkDepth); dw.setDeepenSince(req.getDeepenSince());
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 7b052ad..b23ee97 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UserAgent.java
@@ -10,10 +10,6 @@ package org.eclipse.jgit.transport; -import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT; - -import java.util.Set; - import org.eclipse.jgit.util.StringUtils; /** @@ -91,43 +87,6 @@ public static void set(String agent) { userAgent = StringUtils.isEmptyOrNull(agent) ? null : clean(agent); } - /** - * - * @param options - * options - * @param transportAgent - * name of transport agent - * @return The transport agent. - * @deprecated Capabilities with <key>=<value> shape are now - * parsed alongside other capabilities in the ReceivePack flow. - */ - @Deprecated - static String getAgent(Set<String> options, String transportAgent) { - if (options == null || options.isEmpty()) { - return transportAgent; - } - for (String o : options) { - if (o.startsWith(OPTION_AGENT) - && o.length() > OPTION_AGENT.length() - && o.charAt(OPTION_AGENT.length()) == '=') { - return o.substring(OPTION_AGENT.length() + 1); - } - } - return transportAgent; - } - - /** - * - * @param options - * options - * @return True if the transport agent is set. False otherwise. - * @deprecated Capabilities with <key>=<value> shape are now - * parsed alongside other capabilities in the ReceivePack flow. - */ - @Deprecated - static boolean hasAgent(Set<String> options) { - return getAgent(options, null) != null; - } private UserAgent() { }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java index 3da76f3..b7bb0cb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -22,8 +22,10 @@ import java.util.Deque; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.eclipse.jgit.errors.CompoundException; @@ -122,7 +124,7 @@ class WalkFetchConnection extends BaseFetchConnection { private final Deque<WalkRemoteObjectDatabase> noAlternatesYet; /** Packs we have discovered, but have not yet fetched locally. */ - private final Deque<RemotePack> unfetchedPacks; + private final Map<String, RemotePack> unfetchedPacks; /** * Packs whose indexes we have looked at in {@link #unfetchedPacks}. @@ -164,7 +166,7 @@ class WalkFetchConnection extends BaseFetchConnection { remotes = new ArrayList<>(); remotes.add(w); - unfetchedPacks = new ArrayDeque<>(); + unfetchedPacks = new LinkedHashMap<>(); packsConsidered = new HashSet<>(); noPacksYet = new ArrayDeque<>(); @@ -227,7 +229,7 @@ public void setPackLockMessage(String message) { public void close() { inserter.close(); reader.close(); - for (RemotePack p : unfetchedPacks) { + for (RemotePack p : unfetchedPacks.values()) { if (p.tmpIdx != null) p.tmpIdx.delete(); } @@ -422,8 +424,9 @@ private void downloadObject(ProgressMonitor pm, AnyObjectId id) if (packNameList == null || packNameList.isEmpty()) continue; for (String packName : packNameList) { - if (packsConsidered.add(packName)) - unfetchedPacks.add(new RemotePack(wrr, packName)); + if (packsConsidered.add(packName)) { + unfetchedPacks.put(packName, new RemotePack(wrr, packName)); + } } if (downloadPackedObject(pm, id)) return; @@ -466,15 +469,27 @@ private boolean alreadyHave(AnyObjectId id) throws TransportException { } } + private boolean downloadPackedObject(ProgressMonitor monitor, + AnyObjectId id) throws TransportException { + Set<String> brokenPacks = new HashSet<>(); + try { + return downloadPackedObject(monitor, id, brokenPacks); + } finally { + brokenPacks.forEach(unfetchedPacks::remove); + } + } + @SuppressWarnings("Finally") private boolean downloadPackedObject(final ProgressMonitor monitor, - final AnyObjectId id) throws TransportException { + final AnyObjectId id, Set<String> brokenPacks) throws TransportException { // Search for the object in a remote pack whose index we have, // but whose pack we do not yet have. // - final Iterator<RemotePack> packItr = unfetchedPacks.iterator(); - while (packItr.hasNext() && !monitor.isCancelled()) { - final RemotePack pack = packItr.next(); + for (Entry<String, RemotePack> entry : unfetchedPacks.entrySet()) { + if (monitor.isCancelled()) { + break; + } + final RemotePack pack = entry.getValue(); try { pack.openIndex(monitor); } catch (IOException err) { @@ -484,7 +499,7 @@ private boolean downloadPackedObject(final ProgressMonitor monitor, // another source, so don't consider it a failure. // recordError(id, err); - packItr.remove(); + brokenPacks.add(entry.getKey()); continue; } @@ -535,7 +550,7 @@ private boolean downloadPackedObject(final ProgressMonitor monitor, } throw new TransportException(e.getMessage(), e); } - packItr.remove(); + brokenPacks.add(entry.getKey()); } if (!alreadyHave(id)) { @@ -550,11 +565,9 @@ private boolean downloadPackedObject(final ProgressMonitor monitor, // Complete any other objects that we can. // - final Iterator<ObjectId> pending = swapFetchQueue(); - while (pending.hasNext()) { - final ObjectId p = pending.next(); + final Deque<ObjectId> pending = swapFetchQueue(); + for (ObjectId p : pending) { if (pack.index.hasObject(p)) { - pending.remove(); process(p); } else { workQueue.add(p); @@ -566,8 +579,8 @@ private boolean downloadPackedObject(final ProgressMonitor monitor, return false; } - private Iterator<ObjectId> swapFetchQueue() { - final Iterator<ObjectId> r = workQueue.iterator(); + private Deque<ObjectId> swapFetchQueue() { + final Deque<ObjectId> r = workQueue; workQueue = new ArrayDeque<>(); return r; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java index 125ee6c..95b8221 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java
@@ -36,29 +36,39 @@ */ public interface HttpConnection { /** + * HttpURLConnection#HTTP_OK + * * @see HttpURLConnection#HTTP_OK */ int HTTP_OK = java.net.HttpURLConnection.HTTP_OK; /** + * HttpURLConnection#HTTP_NOT_AUTHORITATIVE + * * @see HttpURLConnection#HTTP_NOT_AUTHORITATIVE * @since 5.8 */ int HTTP_NOT_AUTHORITATIVE = java.net.HttpURLConnection.HTTP_NOT_AUTHORITATIVE; /** + * HttpURLConnection#HTTP_MOVED_PERM + * * @see HttpURLConnection#HTTP_MOVED_PERM * @since 4.7 */ int HTTP_MOVED_PERM = java.net.HttpURLConnection.HTTP_MOVED_PERM; /** + * HttpURLConnection#HTTP_MOVED_TEMP + * * @see HttpURLConnection#HTTP_MOVED_TEMP * @since 4.9 */ int HTTP_MOVED_TEMP = java.net.HttpURLConnection.HTTP_MOVED_TEMP; /** + * HttpURLConnection#HTTP_SEE_OTHER + * * @see HttpURLConnection#HTTP_SEE_OTHER * @since 4.9 */ @@ -85,16 +95,22 @@ public interface HttpConnection { int HTTP_11_MOVED_PERM = 308; /** + * HttpURLConnection#HTTP_NOT_FOUND + * * @see HttpURLConnection#HTTP_NOT_FOUND */ int HTTP_NOT_FOUND = java.net.HttpURLConnection.HTTP_NOT_FOUND; /** + * HttpURLConnection#HTTP_UNAUTHORIZED + * * @see HttpURLConnection#HTTP_UNAUTHORIZED */ int HTTP_UNAUTHORIZED = java.net.HttpURLConnection.HTTP_UNAUTHORIZED; /** + * HttpURLConnection#HTTP_FORBIDDEN + * * @see HttpURLConnection#HTTP_FORBIDDEN */ int HTTP_FORBIDDEN = java.net.HttpURLConnection.HTTP_FORBIDDEN;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java index 36fa720..0cac374 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
@@ -371,12 +371,6 @@ public long getLength() { return attributes.getLength(); } - @Override - @Deprecated - public long getLastModified() { - return attributes.getLastModifiedInstant().toEpochMilli(); - } - /** * @since 5.1.9 */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java index aaac2a7..31c216b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -38,12 +38,12 @@ import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; @@ -1587,10 +1587,16 @@ public String getSmudgeCommand(Attributes attributes) throws IOException { */ private String getFilterCommandDefinition(String filterDriverName, String filterCommandType) { + if (config == null) { + return null; + } String key = filterDriverName + "." + filterCommandType; //$NON-NLS-1$ String filterCommand = filterCommandsByNameDotType.get(key); if (filterCommand != null) return filterCommand; + if (config == null) { + return null; + } filterCommand = config.getString(ConfigConstants.CONFIG_FILTER_SECTION, filterDriverName, filterCommandType); boolean useBuiltin = config.getBoolean(
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 73a3dda..f16d800 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -498,6 +498,8 @@ private InputStream filterClean(InputStream in) filterProcessBuilder.directory(repository.getWorkTree()); filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY, repository.getDirectory().getAbsolutePath()); + filterProcessBuilder.environment().put(Constants.GIT_COMMON_DIR_KEY, + repository.getCommonDirectory().getAbsolutePath()); ExecutionResult result; try { result = fs.execute(filterProcessBuilder, in); @@ -620,18 +622,6 @@ public long getEntryContentLength() throws IOException { /** * Get the last modified time of this entry. * - * @return last modified time of this file, in milliseconds since the epoch - * (Jan 1, 1970 UTC). - * @deprecated use {@link #getEntryLastModifiedInstant()} instead - */ - @Deprecated - public long getEntryLastModified() { - return current().getLastModified(); - } - - /** - * Get the last modified time of this entry. - * * @return last modified time of this file * @since 5.1.9 */ @@ -1229,21 +1219,6 @@ public String toString() { * needs to compute the value they should cache the reference within an * instance member instead. * - * @return time since the epoch (in ms) of the last change. - * @deprecated use {@link #getLastModifiedInstant()} instead - */ - @Deprecated - public abstract long getLastModified(); - - /** - * Get the last modified time of this entry. - * <p> - * <b>Note: Efficient implementation required.</b> - * <p> - * The implementation of this method must be efficient. If a subclass - * needs to compute the value they should cache the reference within an - * instance member instead. - * * @return time of the last change. * @since 5.1.9 */ @@ -1332,7 +1307,7 @@ IgnoreNode load(IgnoreNode parent) throws IOException { IgnoreNode infoExclude = new IgnoreNodeWithParent( coreExclude); - File exclude = fs.resolve(repository.getDirectory(), + File exclude = fs.resolve(repository.getCommonDirectory(), Constants.INFO_EXCLUDE); if (fs.exists(exclude)) { loadRulesFromFile(infoExclude, exclude);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java index bcf79a2..33db6ea 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java
@@ -13,12 +13,12 @@ package org.eclipse.jgit.treewalk.filter; -import org.eclipse.jgit.util.RawParseUtils; - import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.jgit.util.RawParseUtils; + /** * Specialized set for byte arrays, interpreted as strings for use in * {@link PathFilterGroup.Group}. Most methods assume the hash is already know @@ -141,13 +141,19 @@ boolean contains(byte[] toFind, int length, int hash) { } /** + * Returns number of arrays in the set + * * @return number of arrays in the set */ int size() { return size; } - /** @return true if {@link #size()} is 0. */ + /** + * Returns true if {@link #size()} is 0 + * + * @return true if {@link #size()} is 0 + */ boolean isEmpty() { return size == 0; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java index 12af374..c8421d6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -86,8 +86,8 @@ public static ObjectId computeChangeId(final ObjectId treeId, } } - private static final Pattern issuePattern = Pattern - .compile("^(Bug|Issue)[a-zA-Z0-9-]*:.*$"); //$NON-NLS-1$ + private static final Pattern signedOffByPattern = Pattern + .compile("^Signed-off-by:.*$"); //$NON-NLS-1$ private static final Pattern footerPattern = Pattern .compile("(^[a-zA-Z0-9-]+:(?!//).*$)"); //$NON-NLS-1$ @@ -159,7 +159,7 @@ public static String insertId(String message, ObjectId changeId, int footerFirstLine = indexOfFirstFooterLine(lines); int insertAfter = footerFirstLine; for (int i = footerFirstLine; i < lines.length; ++i) { - if (issuePattern.matcher(lines[i]).matches()) { + if (!signedOffByPattern.matcher(lines[i]).matches()) { insertAfter = i + 1; continue; }
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 a8e1dae..59bbacf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -30,7 +30,6 @@ import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; -import java.security.AccessControlException; import java.text.MessageFormat; import java.time.Duration; import java.time.Instant; @@ -262,31 +261,6 @@ public static final class FileStoreAttributes { private static final AtomicInteger threadNumber = new AtomicInteger(1); /** - * Don't use the default thread factory of the ForkJoinPool for the - * CompletableFuture; it runs without any privileges, which causes - * trouble if a SecurityManager is present. - * <p> - * Instead use normal daemon threads. They'll belong to the - * SecurityManager's thread group, or use the one of the calling thread, - * as appropriate. - * </p> - * - * @see java.util.concurrent.Executors#newCachedThreadPool() - */ - private static final ExecutorService FUTURE_RUNNER = new ThreadPoolExecutor( - 5, 5, 30L, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), - runnable -> { - Thread t = new Thread(runnable, - "JGit-FileStoreAttributeReader-" //$NON-NLS-1$ - + threadNumber.getAndIncrement()); - // Make sure these threads don't prevent application/JVM - // shutdown. - t.setDaemon(true); - return t; - }); - - /** * 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 @@ -463,7 +437,7 @@ private static FileStoreAttributes getFileStoreAttributes(Path dir) { locks.remove(s); } return attributes; - }, FUTURE_RUNNER); + }); f = f.exceptionally(e -> { LOG.error(e.getLocalizedMessage(), e); return Optional.empty(); @@ -898,21 +872,6 @@ public static FS detect() { } /** - * Whether FileStore attributes should be determined asynchronously - * - * @param asynch - * whether FileStore attributes should be determined - * asynchronously. If false access to cached attributes may block - * for some seconds for the first call per FileStore - * @since 5.1.9 - * @deprecated Use {@link FileStoreAttributes#setBackground} instead - */ - @Deprecated - public static void setAsyncFileStoreAttributes(boolean asynch) { - FileStoreAttributes.setBackground(asynch); - } - - /** * Auto-detect the appropriate file system abstraction, taking into account * the presence of a Cygwin installation on the system. Using jgit in * combination with Cygwin requires a more elaborate (and possibly slower) @@ -1085,24 +1044,6 @@ private void detectSymlinkSupport() { * symbolic links, the modification time of the link is returned, rather * than that of the link target. * - * @param f - * a {@link java.io.File} object. - * @return last modified time of f - * @throws java.io.IOException - * if an IO error occurred - * @since 3.0 - * @deprecated use {@link #lastModifiedInstant(Path)} instead - */ - @Deprecated - public long lastModified(File f) throws IOException { - return FileUtils.lastModified(f); - } - - /** - * Get the last modified time of a file system object. If the OS/JRE support - * symbolic links, the modification time of the link is returned, rather - * than that of the link target. - * * @param p * a {@link Path} object. * @return last modified time of p @@ -1131,25 +1072,6 @@ public Instant lastModifiedInstant(File f) { * <p> * For symlinks it sets the modified time of the link target. * - * @param f - * a {@link java.io.File} object. - * @param time - * last modified time - * @throws java.io.IOException - * if an IO error occurred - * @since 3.0 - * @deprecated use {@link #setLastModified(Path, Instant)} instead - */ - @Deprecated - public void setLastModified(File f, long time) throws IOException { - FileUtils.setLastModified(f, time); - } - - /** - * 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. * @param time @@ -1443,13 +1365,6 @@ protected static String readPipe(File dir, String[] command, } } catch (IOException e) { LOG.error("Caught exception in FS.readPipe()", e); //$NON-NLS-1$ - } catch (AccessControlException e) { - LOG.warn(MessageFormat.format( - JGitText.get().readPipeIsNotAllowedRequiredPermission, - command, dir, e.getPermission())); - } catch (SecurityException e) { - LOG.warn(MessageFormat.format(JGitText.get().readPipeIsNotAllowed, - command, dir)); } if (debug) { LOG.debug("readpipe returns null"); //$NON-NLS-1$ @@ -1800,25 +1715,6 @@ public void createSymLink(File path, String target) throws IOException { } /** - * Create a new file. See {@link java.io.File#createNewFile()}. Subclasses - * of this class may take care to provide a safe implementation for this - * even if {@link #supportsAtomicCreateNewFile()} is <code>false</code> - * - * @param path - * the file to be created - * @return <code>true</code> if the file was created, <code>false</code> if - * the file already existed - * @throws java.io.IOException - * if an IO error occurred - * @deprecated use {@link #createNewFileAtomic(File)} instead - * @since 4.5 - */ - @Deprecated - public boolean createNewFile(File path) throws IOException { - return path.createNewFile(); - } - - /** * A token representing a file created by * {@link #createNewFileAtomic(File)}. The token must be retained until the * file has been deleted in order to guarantee that the unique file was @@ -2042,6 +1938,8 @@ protected ProcessResult internalRunHookIfPresent(Repository repository, environment.put(Constants.GIT_DIR_KEY, repository.getDirectory().getAbsolutePath()); if (!repository.isBare()) { + environment.put(Constants.GIT_COMMON_DIR_KEY, + repository.getCommonDirectory().getAbsolutePath()); environment.put(Constants.GIT_WORK_TREE_KEY, repository.getWorkTree().getAbsolutePath()); } @@ -2137,7 +2035,7 @@ private File getRunDirectory(Repository repository, case "post-receive": //$NON-NLS-1$ case "post-update": //$NON-NLS-1$ case "push-to-checkout": //$NON-NLS-1$ - return repository.getDirectory(); + return repository.getCommonDirectory(); default: return repository.getWorkTree(); } @@ -2150,7 +2048,7 @@ private File getHooksDirectory(Repository repository) { if (hooksDir != null) { return new File(hooksDir); } - File dir = repository.getDirectory(); + File dir = repository.getCommonDirectory(); return dir == null ? null : new File(dir, Constants.HOOKS); } @@ -2424,19 +2322,6 @@ public long getCreationTime() { } /** - * Get the time when the file was last modified in milliseconds since - * the epoch - * - * @return the time (milliseconds since 1970-01-01) when this object was - * last modified - * @deprecated use getLastModifiedInstant instead - */ - @Deprecated - public long getLastModifiedTime() { - return lastModifiedInstant.toEpochMilli(); - } - - /** * Get the time when this object was last modified * * @return the time when this object was last modified @@ -2578,6 +2463,33 @@ public String normalize(String name) { } /** + * Get common dir path. + * + * @param dir + * the .git folder + * @return common dir path + * @throws IOException + * if commondir file can't be read + * + * @since 7.0 + */ + public File getCommonDir(File dir) throws IOException { + // first the GIT_COMMON_DIR is same as GIT_DIR + File commonDir = dir; + // now check if commondir file exists (e.g. worktree repository) + File commonDirFile = new File(dir, Constants.COMMONDIR_FILE); + if (commonDirFile.isFile()) { + String commonDirPath = new String(IO.readFully(commonDirFile)) + .trim(); + commonDir = new File(commonDirPath); + if (!commonDir.isAbsolute()) { + commonDir = new File(dir, commonDirPath).getCanonicalFile(); + } + } + return commonDir; + } + + /** * This runnable will consume an input stream's content into an output * stream as soon as it gets available. * <p>
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 ee907f2..db2b5b4 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
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Robin Rosenberg and others + * Copyright (C) 2010, 2024, 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 @@ -203,7 +203,16 @@ public boolean supportsExecute() { /** {@inheritDoc} */ @Override public boolean canExecute(File f) { - return FileUtils.canExecute(f); + if (!isFile(f)) { + return false; + } + try { + Path path = FileUtils.toPath(f); + Set<PosixFilePermission> pset = Files.getPosixFilePermissions(path); + return pset.contains(PosixFilePermission.OWNER_EXECUTE); + } catch (IOException ex) { + return false; + } } /** {@inheritDoc} */ @@ -332,73 +341,6 @@ public boolean supportsAtomicCreateNewFile() { return supportsAtomicFileCreation == AtomicFileCreation.SUPPORTED; } - @Override - @SuppressWarnings("boxing") - /** - * {@inheritDoc} - * <p> - * An implementation of the File#createNewFile() semantics which works also - * on NFS. If the config option - * {@code core.supportsAtomicCreateNewFile = true} (which is the default) - * then simply File#createNewFile() is called. - * - * But if {@code core.supportsAtomicCreateNewFile = false} then after - * successful creation of the lock file a hard link to that lock file is - * created and the attribute nlink of the lock file is checked to be 2. If - * multiple clients manage to create the same lock file nlink would be - * greater than 2 showing the error. - * - * @see "https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html" - * - * @deprecated use {@link FS_POSIX#createNewFileAtomic(File)} instead - * @since 4.5 - */ - @Deprecated - public boolean createNewFile(File lock) throws IOException { - if (!lock.createNewFile()) { - return false; - } - if (supportsAtomicCreateNewFile()) { - return true; - } - Path lockPath = lock.toPath(); - Path link = null; - FileStore store = null; - try { - store = Files.getFileStore(lockPath); - } catch (SecurityException e) { - return true; - } - try { - Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store, - s -> Boolean.TRUE); - if (Boolean.FALSE.equals(canLink)) { - return true; - } - link = Files.createLink( - Paths.get(lock.getAbsolutePath() + ".lnk"), //$NON-NLS-1$ - lockPath); - Integer nlink = (Integer) Files.getAttribute(lockPath, - "unix:nlink"); //$NON-NLS-1$ - if (nlink > 2) { - LOG.warn(MessageFormat.format( - JGitText.get().failedAtomicFileCreation, lockPath, - nlink)); - return false; - } else if (nlink < 2) { - CAN_HARD_LINK.put(store, Boolean.FALSE); - } - return true; - } catch (UnsupportedOperationException | IllegalArgumentException e) { - CAN_HARD_LINK.put(store, Boolean.FALSE); - return true; - } finally { - if (link != null) { - Files.delete(link); - } - } - } - /** * {@inheritDoc} * <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java index 635351a..2378791 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
@@ -14,8 +14,6 @@ import java.io.File; import java.io.OutputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -43,10 +41,7 @@ public class FS_Win32_Cygwin extends FS_Win32 { * @return true if cygwin is found */ public static boolean isCygwin() { - final String path = AccessController - .doPrivileged((PrivilegedAction<String>) () -> System - .getProperty("java.library.path") //$NON-NLS-1$ - ); + final String path = System.getProperty("java.library.path"); //$NON-NLS-1$ if (path == null) return false; File found = FS.searchPath(path, "cygpath.exe"); //$NON-NLS-1$ @@ -99,9 +94,7 @@ public File resolve(File dir, String pn) { @Override protected File userHomeImpl() { - final String home = AccessController.doPrivileged( - (PrivilegedAction<String>) () -> System.getenv("HOME") //$NON-NLS-1$ - ); + final String home = System.getenv("HOME"); //$NON-NLS-1$ if (home == null || home.length() == 0) return super.userHomeImpl(); return resolve(new File("."), home); //$NON-NLS-1$
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 cab0e6a..39c67f1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -771,24 +771,6 @@ static boolean isSymlink(File file) { } /** - * Get the lastModified attribute for a given file - * - * @param file - * the file - * @return lastModified attribute for given file, not following symbolic - * links - * @throws IOException - * if an IO error occurred - * @deprecated use {@link #lastModifiedInstant(Path)} instead which returns - * FileTime - */ - @Deprecated - static long lastModified(File file) throws IOException { - return Files.getLastModifiedTime(toPath(file), LinkOption.NOFOLLOW_LINKS) - .toMillis(); - } - - /** * Get last modified timestamp of a file * * @param path @@ -830,21 +812,6 @@ static BasicFileAttributes fileAttributes(File file) throws IOException { /** * Set the last modified time of a file system object. * - * @param file - * the file - * @param time - * last modified timestamp - * @throws IOException - * if an IO error occurred - */ - @Deprecated - static void setLastModified(File file, long time) throws IOException { - Files.setLastModifiedTime(toPath(file), FileTime.fromMillis(time)); - } - - /** - * Set the last modified time of a file system object. - * * @param path * file path * @param time
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java index e6bf497..332e659 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateFormatter.java
@@ -10,10 +10,10 @@ package org.eclipse.jgit.util; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.Locale; -import java.util.TimeZone; import org.eclipse.jgit.lib.PersonIdent; @@ -26,9 +26,9 @@ */ public class GitDateFormatter { - private DateFormat dateTimeInstance; + private DateTimeFormatter dateTimeFormat; - private DateFormat dateTimeInstance2; + private DateTimeFormatter dateTimeFormat2; private final Format format; @@ -96,30 +96,34 @@ public GitDateFormatter(Format format) { default: break; case DEFAULT: // Not default: - dateTimeInstance = new SimpleDateFormat( + dateTimeFormat = DateTimeFormatter.ofPattern( "EEE MMM dd HH:mm:ss yyyy Z", Locale.US); //$NON-NLS-1$ break; case ISO: - dateTimeInstance = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", //$NON-NLS-1$ + dateTimeFormat = DateTimeFormatter.ofPattern( + "yyyy-MM-dd HH:mm:ss Z", //$NON-NLS-1$ Locale.US); break; case LOCAL: - dateTimeInstance = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", //$NON-NLS-1$ + dateTimeFormat = DateTimeFormatter.ofPattern( + "EEE MMM dd HH:mm:ss yyyy", //$NON-NLS-1$ Locale.US); break; case RFC: - dateTimeInstance = new SimpleDateFormat( + dateTimeFormat = DateTimeFormatter.ofPattern( "EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); //$NON-NLS-1$ break; case SHORT: - dateTimeInstance = new SimpleDateFormat("yyyy-MM-dd", Locale.US); //$NON-NLS-1$ + dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd", //$NON-NLS-1$ + Locale.US); break; case LOCALE: case LOCALELOCAL: - SystemReader systemReader = SystemReader.getInstance(); - dateTimeInstance = systemReader.getDateTimeInstance( - DateFormat.DEFAULT, DateFormat.DEFAULT); - dateTimeInstance2 = systemReader.getSimpleDateFormat("Z"); //$NON-NLS-1$ + dateTimeFormat = DateTimeFormatter + .ofLocalizedDateTime(FormatStyle.MEDIUM) + .withLocale(Locale.US); + dateTimeFormat2 = DateTimeFormatter.ofPattern("Z", //$NON-NLS-1$ + Locale.US); break; } } @@ -135,39 +139,45 @@ public GitDateFormatter(Format format) { @SuppressWarnings("boxing") public String formatDate(PersonIdent ident) { switch (format) { - case RAW: - int offset = ident.getTimeZoneOffset(); + case RAW: { + int offset = ident.getZoneOffset().getTotalSeconds(); String sign = offset < 0 ? "-" : "+"; //$NON-NLS-1$ //$NON-NLS-2$ int offset2; - if (offset < 0) + if (offset < 0) { offset2 = -offset; - else + } else { offset2 = offset; - int hours = offset2 / 60; - int minutes = offset2 % 60; + } + int minutes = (offset2 / 60) % 60; + int hours = offset2 / 60 / 60; return String.format("%d %s%02d%02d", //$NON-NLS-1$ - ident.getWhen().getTime() / 1000, sign, hours, minutes); + ident.getWhenAsInstant().getEpochSecond(), sign, hours, + minutes); + } case RELATIVE: - return RelativeDateFormatter.format(ident.getWhen()); + return RelativeDateFormatter.format(ident.getWhenAsInstant()); case LOCALELOCAL: case LOCAL: - dateTimeInstance.setTimeZone(SystemReader.getInstance() - .getTimeZone()); - return dateTimeInstance.format(ident.getWhen()); - case LOCALE: - TimeZone tz = ident.getTimeZone(); - if (tz == null) - tz = SystemReader.getInstance().getTimeZone(); - dateTimeInstance.setTimeZone(tz); - dateTimeInstance2.setTimeZone(tz); - return dateTimeInstance.format(ident.getWhen()) + " " //$NON-NLS-1$ - + dateTimeInstance2.format(ident.getWhen()); - default: - tz = ident.getTimeZone(); - if (tz == null) - tz = SystemReader.getInstance().getTimeZone(); - dateTimeInstance.setTimeZone(ident.getTimeZone()); - return dateTimeInstance.format(ident.getWhen()); + return dateTimeFormat + .withZone(SystemReader.getInstance().getTimeZoneId()) + .format(ident.getWhenAsInstant()); + case LOCALE: { + ZoneId tz = ident.getZoneId(); + if (tz == null) { + tz = SystemReader.getInstance().getTimeZoneId(); + } + return dateTimeFormat.withZone(tz).format(ident.getWhenAsInstant()) + + " " //$NON-NLS-1$ + + dateTimeFormat2.withZone(tz) + .format(ident.getWhenAsInstant()); + } + default: { + ZoneId tz = ident.getZoneId(); + if (tz == null) { + tz = SystemReader.getInstance().getTimeZoneId(); + } + return dateTimeFormat.withZone(tz).format(ident.getWhenAsInstant()); + } } } }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java index 6a4b396..f080056 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
@@ -28,7 +28,10 @@ * used. One example is the parsing of the config parameter gc.pruneexpire. The * parser can handle only subset of what native gits approxidate parser * understands. + * + * @deprecated Use {@link GitTimeParser} instead. */ +@Deprecated(since = "7.1") public class GitDateParser { /** * The Date representing never. Though this is a concrete value, most
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java new file mode 100644 index 0000000..acaa1ce --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java
@@ -0,0 +1,248 @@ +/* + * Copyright (C) 2024 Christian Halstrick 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; + +import java.text.MessageFormat; +import java.text.ParseException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.EnumMap; +import java.util.Map; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.internal.JGitText; + +/** + * Parses strings with time and date specifications into + * {@link java.time.Instant}. + * + * When git needs to parse strings specified by the user this parser can be + * used. One example is the parsing of the config parameter gc.pruneexpire. The + * parser can handle only subset of what native gits approxidate parser + * understands. + * + * @since 7.1 + */ +public class GitTimeParser { + + private static final Map<ParseableSimpleDateFormat, DateTimeFormatter> formatCache = new EnumMap<>( + ParseableSimpleDateFormat.class); + + // An enum of all those formats which this parser can parse with the help of + // a DateTimeFormatter. There are other formats (e.g. the relative formats + // like "yesterday" or "1 week ago") which this parser can parse but which + // are not listed here because they are parsed without the help of a + // DateTimeFormatter. + enum ParseableSimpleDateFormat { + ISO("yyyy-MM-dd HH:mm:ss Z"), // //$NON-NLS-1$ + RFC("EEE, dd MMM yyyy HH:mm:ss Z"), // //$NON-NLS-1$ + SHORT("yyyy-MM-dd"), // //$NON-NLS-1$ + SHORT_WITH_DOTS_REVERSE("dd.MM.yyyy"), // //$NON-NLS-1$ + SHORT_WITH_DOTS("yyyy.MM.dd"), // //$NON-NLS-1$ + SHORT_WITH_SLASH("MM/dd/yyyy"), // //$NON-NLS-1$ + DEFAULT("EEE MMM dd HH:mm:ss yyyy Z"), // //$NON-NLS-1$ + LOCAL("EEE MMM dd HH:mm:ss yyyy"); //$NON-NLS-1$ + + private final String formatStr; + + ParseableSimpleDateFormat(String formatStr) { + this.formatStr = formatStr; + } + } + + private GitTimeParser() { + // This class is not supposed to be instantiated + } + + /** + * Parses a string into a {@link java.time.LocalDateTime} using the default + * locale. Since this parser also supports relative formats (e.g. + * "yesterday") the caller can specify the reference date. These types of + * strings can be parsed: + * <ul> + * <li>"never"</li> + * <li>"now"</li> + * <li>"yesterday"</li> + * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br> + * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of ' + * ' one can use '.' to separate the words</li> + * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li> + * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li> + * <li>"yyyy-MM-dd"</li> + * <li>"yyyy.MM.dd"</li> + * <li>"MM/dd/yyyy",</li> + * <li>"dd.MM.yyyy"</li> + * <li>"EEE MMM dd HH:mm:ss yyyy Z" (DEFAULT)</li> + * <li>"EEE MMM dd HH:mm:ss yyyy" (LOCAL)</li> + * </ul> + * + * @param dateStr + * the string to be parsed + * @return the parsed {@link java.time.LocalDateTime} + * @throws java.text.ParseException + * if the given dateStr was not recognized + */ + public static LocalDateTime parse(String dateStr) throws ParseException { + return parse(dateStr, SystemReader.getInstance().civilNow()); + } + + /** + * Parses a string into a {@link java.time.Instant} using the default + * locale. Since this parser also supports relative formats (e.g. + * "yesterday") the caller can specify the reference date. These types of + * strings can be parsed: + * <ul> + * <li>"never"</li> + * <li>"now"</li> + * <li>"yesterday"</li> + * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br> + * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of ' + * ' one can use '.' to separate the words</li> + * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li> + * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li> + * <li>"yyyy-MM-dd"</li> + * <li>"yyyy.MM.dd"</li> + * <li>"MM/dd/yyyy",</li> + * <li>"dd.MM.yyyy"</li> + * <li>"EEE MMM dd HH:mm:ss yyyy Z" (DEFAULT)</li> + * <li>"EEE MMM dd HH:mm:ss yyyy" (LOCAL)</li> + * </ul> + * + * @param dateStr + * the string to be parsed + * @return the parsed {@link java.time.Instant} + * @throws java.text.ParseException + * if the given dateStr was not recognized + * @since 7.2 + */ + public static Instant parseInstant(String dateStr) throws ParseException { + return parse(dateStr).atZone(SystemReader.getInstance().getTimeZoneId()) + .toInstant(); + } + + // Only tests seem to use this method + static LocalDateTime parse(String dateStr, LocalDateTime now) + throws ParseException { + dateStr = dateStr.trim(); + + if (dateStr.equalsIgnoreCase("never")) { //$NON-NLS-1$ + return LocalDateTime.MAX; + } + LocalDateTime ret = parseRelative(dateStr, now); + if (ret != null) { + return ret; + } + for (ParseableSimpleDateFormat f : ParseableSimpleDateFormat.values()) { + try { + return parseSimple(dateStr, f); + } catch (DateTimeParseException e) { + // simply proceed with the next parser + } + } + ParseableSimpleDateFormat[] values = ParseableSimpleDateFormat.values(); + StringBuilder allFormats = new StringBuilder("\"") //$NON-NLS-1$ + .append(values[0].formatStr); + for (int i = 1; i < values.length; i++) { + allFormats.append("\", \"").append(values[i].formatStr); //$NON-NLS-1$ + } + allFormats.append("\""); //$NON-NLS-1$ + throw new ParseException( + MessageFormat.format(JGitText.get().cannotParseDate, dateStr, + allFormats.toString()), + 0); + } + + // tries to parse a string with the formats supported by DateTimeFormatter + private static LocalDateTime parseSimple(String dateStr, + ParseableSimpleDateFormat f) throws DateTimeParseException { + DateTimeFormatter dateFormat = formatCache.computeIfAbsent(f, + format -> DateTimeFormatter + .ofPattern(f.formatStr) + .withLocale(SystemReader.getInstance().getLocale())); + TemporalAccessor parsed = dateFormat.parse(dateStr); + return parsed.isSupported(ChronoField.HOUR_OF_DAY) + ? LocalDateTime.from(parsed) + : LocalDate.from(parsed).atStartOfDay(); + } + + // tries to parse a string with a relative time specification + @SuppressWarnings("nls") + @Nullable + private static LocalDateTime parseRelative(String dateStr, + LocalDateTime now) { + // check for the static words "yesterday" or "now" + if (dateStr.equals("now")) { + return now; + } + + if (dateStr.equals("yesterday")) { + return now.minusDays(1); + } + + // parse constructs like "3 days ago", "5.week.2.day.ago" + String[] parts = dateStr.split("\\.| ", -1); + int partsLength = parts.length; + // check we have an odd number of parts (at least 3) and that the last + // part is "ago" + if (partsLength < 3 || (partsLength & 1) == 0 + || !parts[parts.length - 1].equals("ago")) { + return null; + } + int number; + for (int i = 0; i < parts.length - 2; i += 2) { + try { + number = Integer.parseInt(parts[i]); + } catch (NumberFormatException e) { + return null; + } + if (parts[i + 1] == null) { + return null; + } + switch (parts[i + 1]) { + case "year": + case "years": + now = now.minusYears(number); + break; + case "month": + case "months": + now = now.minusMonths(number); + break; + case "week": + case "weeks": + now = now.minusWeeks(number); + break; + case "day": + case "days": + now = now.minusDays(number); + break; + case "hour": + case "hours": + now = now.minusHours(number); + break; + case "minute": + case "minutes": + now = now.minusMinutes(number); + break; + case "second": + case "seconds": + now = now.minusSeconds(number); + break; + default: + return null; + } + } + return now; + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java index 46d0bc8..3ed7251 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -13,6 +13,8 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.time.Instant.EPOCH; +import static java.time.ZoneOffset.UTC; import static org.eclipse.jgit.lib.ObjectChecker.author; import static org.eclipse.jgit.lib.ObjectChecker.committer; import static org.eclipse.jgit.lib.ObjectChecker.encoding; @@ -30,6 +32,10 @@ import java.nio.charset.CodingErrorAction; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -44,14 +50,6 @@ * Handy utility functions to parse raw object contents. */ public final class RawParseUtils { - /** - * UTF-8 charset constant. - * - * @since 2.2 - * @deprecated use {@link java.nio.charset.StandardCharsets#UTF_8} instead - */ - @Deprecated - public static final Charset UTF8_CHARSET = UTF_8; private static final byte[] digits10; @@ -467,6 +465,29 @@ public static final int parseTimeZoneOffset(final byte[] b, int ptr, } /** + * Parse a Git style timezone string in [+-]hhmm format + * + * @param b + * buffer to scan. + * @param ptr + * position within buffer to start parsing digits at. + * @param ptrResult + * optional location to return the new ptr value through. If null + * the ptr value will be discarded. + * @return the ZoneOffset represention of the timezone offset string. + * Invalid offsets default to UTC. + */ + private static ZoneId parseZoneOffset(final byte[] b, int ptr, + MutableInteger ptrResult) { + int hhmm = parseBase10(b, ptr, ptrResult); + try { + return ZoneOffset.ofHoursMinutes(hhmm / 100, hhmm % 100); + } catch (DateTimeException e) { + return UTC; + } + } + + /** * Locate the first position after a given character. * * @param b @@ -1035,17 +1056,19 @@ public static PersonIdent parsePersonIdent(byte[] raw, int nameB) { // character if there is no trailing LF. final int tzBegin = lastIndexOfTrim(raw, ' ', nextLF(raw, emailE - 1) - 2) + 1; - if (tzBegin <= emailE) // No time/zone, still valid - return new PersonIdent(name, email, 0, 0); + if (tzBegin <= emailE) { // No time/zone, still valid + return new PersonIdent(name, email, EPOCH, UTC); + } final int whenBegin = Math.max(emailE, lastIndexOfTrim(raw, ' ', tzBegin - 1) + 1); - if (whenBegin >= tzBegin - 1) // No time/zone, still valid - return new PersonIdent(name, email, 0, 0); + if (whenBegin >= tzBegin - 1) { // No time/zone, still valid + return new PersonIdent(name, email, EPOCH, UTC); + } - final long when = parseLongBase10(raw, whenBegin, null); - final int tz = parseTimeZoneOffset(raw, tzBegin); - return new PersonIdent(name, email, when * 1000L, tz); + long when = parseLongBase10(raw, whenBegin, null); + return new PersonIdent(name, email, Instant.ofEpochSecond(when), + parseZoneOffset(raw, tzBegin, null)); } /** @@ -1083,16 +1106,16 @@ public static PersonIdent parsePersonIdentOnly(final byte[] raw, name = decode(raw, nameB, stop); final MutableInteger ptrout = new MutableInteger(); - long when; - int tz; + Instant when; + ZoneId tz; if (emailE < stop) { - when = parseLongBase10(raw, emailE + 1, ptrout); - tz = parseTimeZoneOffset(raw, ptrout.value); + when = Instant.ofEpochSecond(parseLongBase10(raw, emailE + 1, ptrout)); + tz = parseZoneOffset(raw, ptrout.value, null); } else { - when = 0; - tz = 0; + when = EPOCH; + tz = UTC; } - return new PersonIdent(name, email, when * 1000L, tz); + return new PersonIdent(name, email, when, tz); } /**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java index 5611b1e..b6b19e0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RelativeDateFormatter.java
@@ -10,6 +10,8 @@ package org.eclipse.jgit.util; import java.text.MessageFormat; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import org.eclipse.jgit.internal.JGitText; @@ -42,12 +44,29 @@ public class RelativeDateFormatter { * @return age of given {@link java.util.Date} compared to now formatted in * the same relative format as returned by * {@code git log --relative-date} + * @deprecated Use {@link #format(Instant)} instead. */ + @Deprecated(since = "7.2") @SuppressWarnings("boxing") public static String format(Date when) { + return format(when.toInstant()); + } - long ageMillis = SystemReader.getInstance().getCurrentTime() - - when.getTime(); + /** + * Get age of given {@link java.time.Instant} compared to now formatted in the + * same relative format as returned by {@code git log --relative-date} + * + * @param when + * an instant to format + * @return age of given instant compared to now formatted in + * the same relative format as returned by + * {@code git log --relative-date} + * @since 7.2 + */ + @SuppressWarnings("boxing") + public static String format(Instant when) { + long ageMillis = Duration + .between(when, SystemReader.getInstance().now()).toMillis(); // shouldn't happen in a perfect world if (ageMillis < 0)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java index cf06172..e3e3e04 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java
@@ -13,8 +13,8 @@ import java.util.Locale; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.lib.GpgSignatureVerifier.SignatureVerification; -import org.eclipse.jgit.lib.GpgSignatureVerifier.TrustLevel; +import org.eclipse.jgit.lib.SignatureVerifier.SignatureVerification; +import org.eclipse.jgit.lib.SignatureVerifier.TrustLevel; import org.eclipse.jgit.lib.PersonIdent; /** @@ -39,29 +39,34 @@ private SignatureUtils() { * to use for dates * @return a textual representation of the {@link SignatureVerification}, * using LF as line separator + * + * @since 7.0 */ public static String toString(SignatureVerification verification, PersonIdent creator, GitDateFormatter formatter) { StringBuilder result = new StringBuilder(); - // Use the creator's timezone for the signature date - PersonIdent dateId = new PersonIdent(creator, - verification.getCreationDate()); - result.append(MessageFormat.format(JGitText.get().verifySignatureMade, - formatter.formatDate(dateId))); - result.append('\n'); + if (verification.creationDate() != null) { + // Use the creator's timezone for the signature date + PersonIdent dateId = new PersonIdent(creator, + verification.creationDate().toInstant()); + result.append( + MessageFormat.format(JGitText.get().verifySignatureMade, + formatter.formatDate(dateId))); + result.append('\n'); + } result.append(MessageFormat.format( JGitText.get().verifySignatureKey, - verification.getKeyFingerprint().toUpperCase(Locale.ROOT))); + verification.keyFingerprint().toUpperCase(Locale.ROOT))); result.append('\n'); - if (!StringUtils.isEmptyOrNull(verification.getSigner())) { + if (!StringUtils.isEmptyOrNull(verification.signer())) { result.append( MessageFormat.format(JGitText.get().verifySignatureIssuer, - verification.getSigner())); + verification.signer())); result.append('\n'); } String msg; - if (verification.getVerified()) { - if (verification.isExpired()) { + if (verification.verified()) { + if (verification.expired()) { msg = JGitText.get().verifySignatureExpired; } else { msg = JGitText.get().verifySignatureGood; @@ -69,14 +74,14 @@ public static String toString(SignatureVerification verification, } else { msg = JGitText.get().verifySignatureBad; } - result.append(MessageFormat.format(msg, verification.getKeyUser())); - if (!TrustLevel.UNKNOWN.equals(verification.getTrustLevel())) { + result.append(MessageFormat.format(msg, verification.keyUser())); + if (!TrustLevel.UNKNOWN.equals(verification.trustLevel())) { result.append(' ' + MessageFormat .format(JGitText.get().verifySignatureTrust, verification - .getTrustLevel().name().toLowerCase(Locale.ROOT))); + .trustLevel().name().toLowerCase(Locale.ROOT))); } result.append('\n'); - msg = verification.getMessage(); + msg = verification.message(); if (!StringUtils.isEmptyOrNull(msg)) { result.append(msg); result.append('\n');
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java index d957deb..efa6e7dd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java
@@ -43,14 +43,18 @@ public void add(double x) { } /** - * @return number of the added values + * Returns the number of added values + * + * @return the number of added values */ public int count() { return n; } /** - * @return minimum of the added values + * Returns the smallest value added + * + * @return the smallest value added */ public double min() { if (n < 1) { @@ -60,7 +64,9 @@ public double min() { } /** - * @return maximum of the added values + * Returns the biggest value added + * + * @return the biggest value added */ public double max() { if (n < 1) { @@ -70,9 +76,10 @@ public double max() { } /** - * @return average of the added values + * Returns the average of the added values + * + * @return the average of the added values */ - public double avg() { if (n < 1) { return Double.NaN; @@ -81,7 +88,9 @@ public double avg() { } /** - * @return variance of the added values + * Returns the variance of the added values + * + * @return the variance of the added values */ public double var() { if (n < 2) { @@ -91,7 +100,9 @@ public double var() { } /** - * @return standard deviation of the added values + * Returns the standard deviation of the added values + * + * @return the standard deviation of the added values */ public double stddev() { return Math.sqrt(this.var());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java index 2fbd12d..e381a3b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
@@ -278,6 +278,44 @@ public static String join(Collection<String> parts, String separator, } /** + * Remove the specified character from beginning and end of a string + * <p> + * If the character repeats, all copies + * + * @param str input string + * @param c character to remove + * @return the input string with c + * @since 7.2 + */ + public static String trim(String str, char c) { + if (str == null || str.length() == 0) { + return str; + } + + int endPos = str.length()-1; + while (endPos >= 0 && str.charAt(endPos) == c) { + endPos--; + } + + // Whole string is c + if (endPos == -1) { + return EMPTY; + } + + int startPos = 0; + while (startPos < endPos && str.charAt(startPos) == c) { + startPos++; + } + + if (startPos == 0 && endPos == str.length()-1) { + // No need to copy + return str; + } + + return str.substring(startPos, endPos+1); + } + + /** * Appends {@link Constants#DOT_GIT_EXT} unless the given name already ends * with that suffix. *
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 ed62c71..22b82b3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -23,10 +23,12 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.Locale; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicReference; @@ -169,6 +171,11 @@ public long getCurrentTime() { } @Override + public Instant now() { + return Instant.now(); + } + + @Override public int getTimezone(long when) { return getTimeZone().getOffset(when) / (60 * 1000); } @@ -230,9 +237,19 @@ public long getCurrentTime() { } @Override + public Instant now() { + return delegate.now(); + } + + @Override public int getTimezone(long when) { return delegate.getTimezone(when); } + + @Override + public ZoneOffset getTimeZoneAt(Instant when) { + return delegate.getTimeZoneAt(when); + } } private static volatile SystemReader INSTANCE = DEFAULT; @@ -503,10 +520,37 @@ private void updateAll(Config config) * Get the current system time * * @return the current system time + * + * @deprecated Use {@link #now()} */ + @Deprecated(since = "7.1") public abstract long getCurrentTime(); /** + * Get the current system time + * + * @return the current system time + * + * @since 7.1 + */ + public Instant now() { + // Subclasses overriding getCurrentTime should keep working + // TODO(ifrade): Once we remove getCurrentTime, use Instant.now() + return Instant.ofEpochMilli(getCurrentTime()); + } + + /** + * Get "now" as civil time, in the System timezone + * + * @return the current system time + * + * @since 7.1 + */ + public LocalDateTime civilNow() { + return LocalDateTime.ofInstant(now(), getTimeZoneId()); + } + + /** * Get clock instance preferred by this system. * * @return clock instance preferred by this system. @@ -522,20 +566,48 @@ public MonotonicClock getClock() { * @param when * a system timestamp * @return the local time zone + * + * @deprecated Use {@link #getTimeZoneAt(Instant)} instead. */ + @Deprecated(since = "7.1") public abstract int getTimezone(long when); /** + * Get the local time zone offset at "when" time + * + * @param when + * a system timestamp + * @return the local time zone + * @since 7.1 + */ + public ZoneOffset getTimeZoneAt(Instant when) { + return getTimeZoneId().getRules().getOffset(when); + } + + /** * Get system time zone, possibly mocked for testing * * @return system time zone, possibly mocked for testing * @since 1.2 + * + * @deprecated Use {@link #getTimeZoneId()} */ + @Deprecated(since = "7.1") public TimeZone getTimeZone() { return TimeZone.getDefault(); } /** + * Get system time zone, possibly mocked for testing + * + * @return system time zone, possibly mocked for testing + * @since 7.1 + */ + public ZoneId getTimeZoneId() { + return ZoneId.systemDefault(); + } + + /** * Get the locale to use * * @return the locale to use @@ -670,9 +742,7 @@ public boolean isPerformanceTraceEnabled() { } private String getOsName() { - return AccessController.doPrivileged( - (PrivilegedAction<String>) () -> getProperty("os.name") //$NON-NLS-1$ - ); + return getProperty("os.name"); //$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 2385865..4b9706a 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
@@ -147,44 +147,6 @@ public AutoLFInputStream(InputStream in, Set<StreamFlag> flags) { && 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. - * - * @param in - * raw input stream - * @param detectBinary - * whether binaries should be detected - * @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; - } - @Override public int read() throws IOException { final int read = read(single, 0, 1);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java index 4764676..13982b1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java
@@ -11,8 +11,6 @@ import java.io.IOException; import java.io.Writer; -import java.security.AccessController; -import java.security.PrivilegedAction; import org.eclipse.jgit.util.SystemReader; @@ -35,10 +33,7 @@ public class ThrowingPrintWriter extends Writer { */ public ThrowingPrintWriter(Writer out) { this.out = out; - LF = AccessController - .doPrivileged((PrivilegedAction<String>) () -> SystemReader - .getInstance().getProperty("line.separator") //$NON-NLS-1$ - ); + LF = SystemReader.getInstance().getProperty("line.separator"); //$NON-NLS-1$ } @Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java index c3a1c4e..7e950f6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java
@@ -14,7 +14,6 @@ import java.io.InputStream; import java.util.ArrayDeque; import java.util.Deque; -import java.util.Iterator; /** * An InputStream which reads from one or more InputStreams. @@ -164,14 +163,14 @@ public long skip(long count) throws IOException { public void close() throws IOException { IOException err = null; - for (Iterator<InputStream> i = streams.iterator(); i.hasNext();) { + for (InputStream stream : streams) { try { - i.next().close(); + stream.close(); } catch (IOException closeError) { err = closeError; } - i.remove(); } + streams.clear(); if (err != null) throw err;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java index a5ee107..a20eaaf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/time/ProposedTimestamp.java
@@ -138,7 +138,10 @@ public Instant instant() { * Get time since epoch, with up to microsecond resolution. * * @return time since epoch, with up to microsecond resolution. + * + * @deprecated Use instant() instead */ + @Deprecated(since = "7.2") public Timestamp timestamp() { return Timestamp.from(instant()); } @@ -147,7 +150,10 @@ public Timestamp timestamp() { * Get time since epoch, with up to millisecond resolution. * * @return time since epoch, with up to millisecond resolution. + * + * @deprecated Use instant() instead */ + @Deprecated(since = "7.2") public Date date() { return new Date(millis()); }
diff --git a/pom.xml b/pom.xml index 590dffa..ecae118 100644 --- a/pom.xml +++ b/pom.xml
@@ -18,7 +18,7 @@ <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> <packaging>pom</packaging> - <version>7.0.0-SNAPSHOT</version> + <version>7.3.0-SNAPSHOT</version> <name>JGit - Parent</name> <url>${jgit-url}</url> @@ -33,8 +33,8 @@ </description> <scm> - <url>https://git.eclipse.org/r/plugins/gitiles/jgit/jgit</url> - <connection>scm:git:https://git.eclipse.org/r/jgit/jgit</connection> + <url>https://eclipse.gerrithub.io/plugins/gitiles/eclipse-jgit/jgit</url> + <connection>scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit</connection> </scm> <ciManagement> @@ -95,8 +95,8 @@ </mailingLists> <issueManagement> - <url>https://bugs.eclipse.org/bugs/buglist.cgi?query_format=advanced;component=JGit;product=JGit;classification=Technology</url> - <system>Bugzilla</system> + <url>https://github.com/eclipse-jgit/jgit/issues</url> + <system>GitHub Issues</system> </issueManagement> <licenses> @@ -118,37 +118,37 @@ <project.build.outputTimestamp>${commit.time.iso}</project.build.outputTimestamp> - <jgit-last-release-version>6.9.0.202403050737-r</jgit-last-release-version> - <ant-version>1.10.14</ant-version> - <apache-sshd-version>2.12.0</apache-sshd-version> + <jgit-last-release-version>7.1.0.202411261347-r</jgit-last-release-version> + <ant-version>1.10.15</ant-version> + <apache-sshd-version>2.15.0</apache-sshd-version> <jsch-version>0.1.55</jsch-version> <jzlib-version>1.1.3</jzlib-version> <javaewah-version>1.2.3</javaewah-version> <junit-version>4.13.2</junit-version> <test-fork-count>1C</test-fork-count> - <args4j-version>2.33</args4j-version> - <commons-compress-version>1.26.0</commons-compress-version> + <args4j-version>2.37</args4j-version> + <commons-compress-version>1.27.1</commons-compress-version> <osgi-core-version>6.0.0</osgi-core-version> - <servlet-api-version>6.0.0</servlet-api-version> - <jetty-version>12.0.9</jetty-version> - <japicmp-version>0.18.5</japicmp-version> + <servlet-api-version>6.1.0</servlet-api-version> + <jetty-version>12.0.16</jetty-version> + <japicmp-version>0.23.1</japicmp-version> <httpclient-version>4.5.14</httpclient-version> <httpcore-version>4.4.16</httpcore-version> <slf4j-version>1.7.36</slf4j-version> - <maven-javadoc-plugin-version>3.6.3</maven-javadoc-plugin-version> - <gson-version>2.10.1</gson-version> - <bouncycastle-version>1.77</bouncycastle-version> - <spotbugs-maven-plugin-version>4.8.3.1</spotbugs-maven-plugin-version> - <maven-project-info-reports-plugin-version>3.5.1</maven-project-info-reports-plugin-version> - <maven-jxr-plugin-version>3.3.2</maven-jxr-plugin-version> - <maven-surefire-plugin-version>3.2.5</maven-surefire-plugin-version> + <maven-javadoc-plugin-version>3.11.2</maven-javadoc-plugin-version> + <gson-version>2.12.1</gson-version> + <bouncycastle-version>1.80</bouncycastle-version> + <spotbugs-maven-plugin-version>4.9.1.0</spotbugs-maven-plugin-version> + <maven-project-info-reports-plugin-version>3.8.0</maven-project-info-reports-plugin-version> + <maven-jxr-plugin-version>3.6.0</maven-jxr-plugin-version> + <maven-surefire-plugin-version>3.5.2</maven-surefire-plugin-version> <maven-surefire-report-plugin-version>${maven-surefire-plugin-version}</maven-surefire-report-plugin-version> - <maven-compiler-plugin-version>3.12.1</maven-compiler-plugin-version> + <maven-compiler-plugin-version>3.14.0</maven-compiler-plugin-version> <plexus-compiler-version>2.13.0</plexus-compiler-version> <hamcrest-version>2.2</hamcrest-version> - <assertj-version>3.25.3</assertj-version> - <jna-version>5.14.0</jna-version> - <byte-buddy-version>1.14.12</byte-buddy-version> + <assertj-version>3.27.3</assertj-version> + <jna-version>5.16.0</jna-version> + <byte-buddy-version>1.17.1</byte-buddy-version> <!-- Properties to enable jacoco code coverage analysis --> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> @@ -184,7 +184,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> - <version>3.3.0</version> + <version>3.4.2</version> <configuration> <archive> <manifestEntries> @@ -208,13 +208,13 @@ <plugin> <artifactId>maven-clean-plugin</artifactId> - <version>3.3.2</version> + <version>3.4.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> - <version>3.5.1</version> + <version>3.6.0</version> </plugin> <plugin> @@ -226,13 +226,13 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> - <version>3.6.1</version> + <version>3.8.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> - <version>3.3.0</version> + <version>3.3.1</version> </plugin> <plugin> @@ -255,7 +255,7 @@ <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> - <version>3.5.0</version> + <version>3.6.0</version> </plugin> <plugin> @@ -277,7 +277,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> - <version>3.21.2</version> + <version>3.26.0</version> <configuration> <inputEncoding>${project.build.sourceEncoding}</inputEncoding> <minimumTokens>100</minimumTokens> @@ -300,17 +300,17 @@ <plugin> <groupId>org.eclipse.cbi.maven.plugins</groupId> <artifactId>eclipse-jarsigner-plugin</artifactId> - <version>1.4.3</version> + <version>1.5.2</version> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.8.11</version> + <version>0.8.12</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> - <version>4.0.0-M13</version> + <version>4.0.0-M16</version> <dependencies> <dependency><!-- add support for ssh/scp --> <groupId>org.apache.maven.wagon</groupId> @@ -337,12 +337,12 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> - <version>3.1.1</version> + <version>3.1.3</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> - <version>3.1.1</version> + <version>3.1.3</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -357,7 +357,7 @@ <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> - <version>2.7.13</version> + <version>3.4.3</version> </plugin> <plugin> <groupId>org.eclipse.dash</groupId> @@ -367,12 +367,12 @@ <plugin> <groupId>org.cyclonedx</groupId> <artifactId>cyclonedx-maven-plugin</artifactId> - <version>2.7.10</version> + <version>2.9.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-artifact-plugin</artifactId> - <version>3.5.0</version> + <version>3.6.0</version> <configuration> <ignore>**/*cyclonedx.json</ignore> <reproducible>true</reproducible> @@ -381,7 +381,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> - <version>3.4.1</version> + <version>3.5.0</version> </plugin> </plugins> </pluginManagement> @@ -623,7 +623,7 @@ <plugin> <groupId>io.github.git-commit-id</groupId> <artifactId>git-commit-id-maven-plugin</artifactId> - <version>7.0.0</version> + <version>9.0.1</version> <executions> <execution> <id>get-the-git-infos</id> @@ -642,18 +642,18 @@ <plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> - <version>3.0.2</version> + <version>4.1.1</version> <dependencies> <dependency> <groupId>org.apache.groovy</groupId> <artifactId>groovy</artifactId> - <version>4.0.15</version> + <version>4.0.21</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apache.groovy</groupId> <artifactId>groovy-ant</artifactId> - <version>4.0.15</version> + <version>4.0.21</version> <scope>runtime</scope> </dependency> </dependencies> @@ -884,15 +884,33 @@ </dependency> <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.18.0</version> + </dependency> + + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>${commons-compress-version}</version> </dependency> <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-io</artifactId> + <version>2.18.0</version> + </dependency> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.3.5</version> + </dependency> + + <dependency> <groupId>org.tukaani</groupId> <artifactId>xz</artifactId> - <version>1.9</version> + <version>1.10</version> <optional>true</optional> </dependency> @@ -989,7 +1007,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.10.0</version> + <version>5.15.2</version> </dependency> <dependency> @@ -1098,7 +1116,7 @@ <dependency> <groupId>org.eclipse.jdt</groupId> <artifactId>ecj</artifactId> - <version>3.36.0</version> + <version>3.40.0</version> </dependency> </dependencies> </plugin>
diff --git a/tools/BUILD b/tools/BUILD index 8c424b3..844f004 100644 --- a/tools/BUILD +++ b/tools/BUILD
@@ -10,6 +10,7 @@ java_runtime = "@rules_java//toolchains:remotejdk_17", package_configuration = [ ":error_prone", + ":error_prone_tests", ], source_version = "17", target_version = "17", @@ -22,6 +23,7 @@ java_runtime = "@rules_java//toolchains:remotejdk_21", package_configuration = [ ":error_prone", + ":error_prone_tests", ], source_version = "21", target_version = "21", @@ -32,9 +34,7 @@ # enabled. This warnings list is originally based on: # https://github.com/bazelbuild/BUILD_file_generator/blob/master/tools/bazel_defs/java.bzl # However, feel free to add any additional errors. Thus far they have all been pretty useful. -java_package_configuration( - name = "error_prone", - javacopts = [ +errorprone_checks = [ "-XepDisableWarningsInGeneratedCode", # The XepDisableWarningsInGeneratedCode disables only warnings, but # not errors. We should manually exclude all files generated by @@ -422,37 +422,57 @@ "-Xep:WrongOneof:ERROR", "-Xep:XorPower:ERROR", "-Xep:ZoneIdOfZ:ERROR", - ], +] + + +exclude_in_tests = ["-Xep:EmptyBlockTag:WARN", + "-Xep:MissingSummary:WARN"] + +java_package_configuration( + name = "error_prone", + javacopts = errorprone_checks, packages = ["error_prone_packages"], ) +java_package_configuration( + name = "error_prone_tests", + javacopts = [ check for check in errorprone_checks if check not in exclude_in_tests], + packages = ["error_prone_packages_test"], +) + package_group( name = "error_prone_packages", packages = [ - "//org.eclipse.jgit.ant.test/...", "//org.eclipse.jgit.ant/...", "//org.eclipse.jgit.archive/...", - "//org.eclipse.jgit.gpg.bc.test/...", "//org.eclipse.jgit.gpg.bc/...", "//org.eclipse.jgit.http.apache/...", "//org.eclipse.jgit.http.server/...", - "//org.eclipse.jgit.http.test/...", "//org.eclipse.jgit.junit.ssh/...", "//org.eclipse.jgit.junit/...", "//org.eclipse.jgit.junit/http/...", - "//org.eclipse.jgit.lfs.server.test/...", "//org.eclipse.jgit.lfs.server/...", - "//org.eclipse.jgit.lfs.test/...", "//org.eclipse.jgit.lfs/...", - "//org.eclipse.jgit.pgm.test/...", "//org.eclipse.jgit.pgm/...", "//org.eclipse.jgit.ssh.apache.agent/...", - "//org.eclipse.jgit.ssh.apache.test/...", "//org.eclipse.jgit.ssh.apache/...", - "//org.eclipse.jgit.ssh.jsch.test/...", "//org.eclipse.jgit.ssh.jsch/...", - "//org.eclipse.jgit.test/...", "//org.eclipse.jgit.ui/...", "//org.eclipse.jgit/...", ], ) + +package_group( + name = "error_prone_packages_test", + packages = [ + "//org.eclipse.jgit.ant.test/...", + "//org.eclipse.jgit.gpg.bc.test/...", + "//org.eclipse.jgit.http.test/...", + "//org.eclipse.jgit.lfs.server.test/...", + "//org.eclipse.jgit.lfs.test/...", + "//org.eclipse.jgit.pgm.test/...", + "//org.eclipse.jgit.ssh.apache.test/...", + "//org.eclipse.jgit.ssh.jsch.test/...", + "//org.eclipse.jgit.test/...", + ], +)
diff --git a/tools/workspace_status.py b/tools/workspace_status.py index ca9e0a9..1186a4a 100644 --- a/tools/workspace_status.py +++ b/tools/workspace_status.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (C) 2020, David Ostrovsky <david@ostrovsky.org> and others # # This program and the accompanying materials are made available under the