diff options
325 files changed, 11792 insertions, 3568 deletions
@@ -1,7 +1,3 @@ -# TODO(davido): Migrate all dependencies from WORKSPACE to MODULE.bazel -# https://issues.gerritcodereview.com/issues/303819949 -common --noenable_bzlmod - build --workspace_status_command="python3 ./tools/workspace_status.py" build --repository_cache=~/.gerritcodereview/bazel-cache/repository build --incompatible_strict_action_env @@ -37,5 +33,6 @@ build:remote21 --config=remote 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/.bazelversion b/.bazelversion index 21c8c7b46b..2b0aa21219 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.1.1 +8.2.1 diff --git a/Documentation/config-options.md b/Documentation/config-options.md index eeb78ff550..4dde8f8c15 100644 --- a/Documentation/config-options.md +++ b/Documentation/config-options.md @@ -55,9 +55,13 @@ For details on native git options see also the official [git config documentatio | `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 @@ -131,6 +135,13 @@ Proxy configuration uses the standard Java mechanisms via class `java.net.ProxyS | `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/MODULE.bazel b/MODULE.bazel index 0b932b8d8c..5fbe2c2ed4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,2 +1,101 @@ -# TODO(davido): Migrate all dependencies from WORKSPACE to MODULE.bazel -# https://issues.gerritcodereview.com/issues/303819949 +module(name = "jgit") + +bazel_dep(name = "rules_java", version = "8.11.0") +bazel_dep(name = "rules_jvm_external", version = "6.7") + +register_toolchains("//tools:error_prone_warnings_toolchain_java17_definition") + +register_toolchains("//tools:error_prone_warnings_toolchain_java21_definition") + +git_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "com_googlesource_gerrit_bazlets", + commit = "f9c119e45d9a241bee720b7fbd6c7fdbc952da5f", + remote = "https://gerrit.googlesource.com/bazlets", +) + +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "ubuntu2204_jdk17", + sha256 = "8ea82b81c9707e535ff93ef5349d11e55b2a23c62bcc3b0faaec052144aed87d", + strip_prefix = "rbe_autoconfig-5.1.0", + urls = [ + "https://gerrit-bazel.storage.googleapis.com/rbe_autoconfig/v5.1.0.tar.gz", + "https://github.com/davido/rbe_autoconfig/releases/download/v5.1.0/v5.1.0.tar.gz", + ], +) + +BOUNCYCASTLE_VERSION = "1.81" + +BYTE_BUDDY_VERSION = "1.17.5" + +JETTY_VERSION = "12.0.22" + +JMH_VERSION = "1.37" + +JNA_VERSION = "5.17.0" + +SLF4J_VERSION = "1.7.36" + +SSHD_VERSION = "2.15.0" + +maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +maven.install( + name = "jgit_deps", + artifacts = [ + "args4j:args4j:2.37", + "com.google.code.gson:gson:2.13.1", + "com.google.errorprone:error_prone_type_annotations:2.38.0", + "com.googlecode.javaewah:JavaEWAH:1.2.3", + "com.jcraft:jsch:0.1.55", + "com.jcraft:jzlib:1.1.3", + "commons-codec:commons-codec:1.18.0", + "commons-io:commons-io:2.19.0", + "commons-logging:commons-logging:1.3.5", + "jakarta.servlet:jakarta.servlet-api:6.1.0", + "junit:junit:4.13.2", + "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, + "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, + "net.java.dev.jna:jna-platform:" + JNA_VERSION, + "net.java.dev.jna:jna:" + JNA_VERSION, + "net.sf.jopt-simple:jopt-simple:5.0.4", + "org.apache.commons:commons-compress:1.27.1", + "org.apache.commons:commons-lang3:3.17.0", + "org.apache.commons:commons-math3:3.6.1", + "org.apache.httpcomponents:httpclient:4.5.14", + "org.apache.httpcomponents:httpcore:4.4.16", + "org.apache.sshd:sshd-osgi:" + SSHD_VERSION, + "org.apache.sshd:sshd-sftp:" + SSHD_VERSION, + "org.assertj:assertj-core:3.27.3", + "org.bouncycastle:bcpg-jdk18on:" + BOUNCYCASTLE_VERSION, + "org.bouncycastle:bcpkix-jdk18on:" + BOUNCYCASTLE_VERSION, + "org.bouncycastle:bcprov-jdk18on:" + BOUNCYCASTLE_VERSION, + "org.bouncycastle:bcutil-jdk18on:" + BOUNCYCASTLE_VERSION, + "org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-http:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-io:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-security:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-server:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-session:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VERSION, + "org.eclipse.jetty:jetty-util:" + JETTY_VERSION, + "org.hamcrest:hamcrest:2.2", + "org.mockito:mockito-core:5.18.0", + "org.objenesis:objenesis:3.4", + "org.openjdk.jmh:jmh-core:" + JMH_VERSION, + "org.openjdk.jmh:jmh-generator-annprocess:" + JMH_VERSION, + "org.slf4j:slf4j-api:" + SLF4J_VERSION, + "org.slf4j:slf4j-simple:" + SLF4J_VERSION, + "org.tukaani:xz:1.10", + ], + duplicate_version_warning = "error", + fail_on_missing_checksum = True, + fetch_sources = True, + repositories = [ + "https://repo1.maven.org/maven2", + ], + strict_visibility = True, +) +use_repo(maven, "jgit_deps") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000000..bdc8104794 --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,221 @@ +{ + "lockFileVersion": 18, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/source.json": "3e8379efaaef53ce35b7b8ba419df829315a880cb0a030e5bb45c96d6d5ecb5f", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/source.json": "4db99b3f55c90ab28d14552aa0632533e3e8e5e9aea0f5c24ac0014282c2a7c5", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad", + "https://bcr.bazel.build/modules/rules_java/8.11.0/source.json": "302b52a39259a85aa06ca3addb9787864ca3e03b432a5f964ea68244397e7544", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.7/MODULE.bazel": "e717beabc4d091ecb2c803c2d341b88590e9116b8bf7947915eeb33aab4f96dd", + "https://bcr.bazel.build/modules/rules_jvm_external/6.7/source.json": "5426f412d0a7fc6b611643376c7e4a82dec991491b9ce5cb1cfdd25fe2e92be4", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": "939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.1/source.json": "b6500ffcd7b48cd72c29bb67bcac781e12701cc0d6d55d266a652583cfcdab01", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@platforms//host:extension.bzl%host_platform": { + "general": { + "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", + "usagesDigest": "SeQiIN/f8/Qt9vYQk7qcXp4I4wJeEC0RnQDiaaJ4tb8=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "host_platform": { + "repoRuleId": "@@platforms//host:extension.bzl%host_platform_repo", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "sFhcgPbDQehmbD1EOXzX4H1q/CD5df8zwG4kp4jbvr8=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin+", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + } +} @@ -1,327 +1,2 @@ -workspace(name = "jgit") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("//tools:bazlets.bzl", "load_bazlets") - -load_bazlets(commit = "f9c119e45d9a241bee720b7fbd6c7fdbc952da5f") - -load( - "@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", - "maven_jar", -) - -http_archive( - name = "rules_java", - sha256 = "4da3761f6855ad916568e2bfe86213ba6d2637f56b8360538a7fb6125abf6518", - urls = [ - "https://github.com/bazelbuild/rules_java/releases/download/7.5.0/rules_java-7.5.0.tar.gz", - ], -) - -load("@rules_java//java:repositories.bzl", "rules_java_dependencies", "rules_java_toolchains") - -rules_java_dependencies() - -http_archive( - name = "ubuntu2204_jdk17", - sha256 = "8ea82b81c9707e535ff93ef5349d11e55b2a23c62bcc3b0faaec052144aed87d", - strip_prefix = "rbe_autoconfig-5.1.0", - urls = [ - "https://gerrit-bazel.storage.googleapis.com/rbe_autoconfig/v5.1.0.tar.gz", - "https://github.com/davido/rbe_autoconfig/releases/download/v5.1.0/v5.1.0.tar.gz", - ], -) - -register_toolchains("//tools:error_prone_warnings_toolchain_java17_definition") - -register_toolchains("//tools:error_prone_warnings_toolchain_java21_definition") - -# Order of registering toolchains matters. rules_java toolchains take precedence -# over the custom toolchains, so the default jdk21 toolchain gets picked -# (one without custom package_config). That's why the `rules_java_toolchains()` -# must be called after the `register_toolchain()` invocation. -rules_java_toolchains() - -JMH_VERS = "1.37" - -maven_jar( - name = "jmh-core", - artifact = "org.openjdk.jmh:jmh-core:" + JMH_VERS, - attach_source = False, - sha1 = "896f27e49105b35ea1964319c83d12082e7a79ef", -) - -maven_jar( - name = "jmh-annotations", - artifact = "org.openjdk.jmh:jmh-generator-annprocess:" + JMH_VERS, - attach_source = False, - sha1 = "da93888682df163144edf9b13d2b78e54166063a", -) - -maven_jar( - name = "jopt", - artifact = "net.sf.jopt-simple:jopt-simple:5.0.4", - attach_source = False, - sha1 = "4fdac2fbe92dfad86aa6e9301736f6b4342a3f5c", -) - -maven_jar( - name = "math3", - artifact = "org.apache.commons:commons-math3:3.6.1", - attach_source = False, - sha1 = "e4ba98f1d4b3c80ec46392f25e094a6a2e58fcbf", -) - -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", -) - -maven_jar( - name = "jzlib", - artifact = "com.jcraft:jzlib:1.1.3", - sha1 = "c01428efa717624f7aabf4df319939dda9646b2d", -) - -maven_jar( - name = "javaewah", - artifact = "com.googlecode.javaewah:JavaEWAH:1.2.3", - sha1 = "13a27c856e0c8808cee9a64032c58eee11c3adc9", -) - -maven_jar( - name = "httpclient", - artifact = "org.apache.httpcomponents:httpclient:4.5.14", - sha1 = "1194890e6f56ec29177673f2f12d0b8e627dec98", -) - -maven_jar( - name = "httpcore", - artifact = "org.apache.httpcomponents:httpcore:4.4.16", - sha1 = "51cf043c87253c9f58b539c9f7e44c8894223850", -) - -SSHD_VERS = "2.14.0" - -maven_jar( - name = "sshd-osgi", - artifact = "org.apache.sshd:sshd-osgi:" + SSHD_VERS, - sha1 = "6ef66228a088f8ac1383b2ff28f3102f80ebc01a", -) - -maven_jar( - name = "sshd-sftp", - artifact = "org.apache.sshd:sshd-sftp:" + SSHD_VERS, - sha1 = "c070ac920e72023ae9ab0a3f3a866bece284b470", -) - -JNA_VERS = "5.15.0" - -maven_jar( - name = "jna", - artifact = "net.java.dev.jna:jna:" + JNA_VERS, - sha1 = "01ee1d80ff44f08280188f7c0e740d57207841ac", -) - -maven_jar( - name = "jna-platform", - artifact = "net.java.dev.jna:jna-platform:" + JNA_VERS, - sha1 = "86b502cad57d45da172b5e3231c537b042e296ef", -) - -maven_jar( - name = "commons-codec", - artifact = "commons-codec:commons-codec:1.17.1", - sha1 = "973638b7149d333563584137ebf13a691bb60579", -) - -maven_jar( - name = "commons-logging", - artifact = "commons-logging:commons-logging:1.3.4", - sha1 = "b9fc14968d63a8b8a8a2c1885fe3e90564239708", -) - -maven_jar( - name = "log-api", - artifact = "org.slf4j:slf4j-api:1.7.36", - sha1 = "6c62681a2f655b49963a5983b8b0950a6120ae14", -) - -maven_jar( - name = "slf4j-simple", - artifact = "org.slf4j:slf4j-simple:1.7.36", - sha1 = "a41f9cfe6faafb2eb83a1c7dd2d0dfd844e2a936", -) - -maven_jar( - name = "servlet-api", - artifact = "jakarta.servlet:jakarta.servlet-api:6.1.0", - sha1 = "1169a246913fe3823782af7943e7a103634867c5", -) - -maven_jar( - name = "commons-compress", - 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.18.0", - sha1 = "44084ef756763795b31c578403dd028ff4a22950", -) - -maven_jar( - name = "tukaani-xz", - artifact = "org.tukaani:xz:1.10", - sha1 = "1be8166f89e035a56c6bfc67dbc423996fe577e2", -) - -maven_jar( - name = "args4j", - artifact = "args4j:args4j:2.37", - sha1 = "244f60c057d72a785227c0562d3560f42a7ea54b", -) - -maven_jar( - name = "junit", - artifact = "junit:junit:4.13.2", - sha1 = "8ac9e16d933b6fb43bc7f576336b8f4d7eb5ba12", -) - -maven_jar( - name = "hamcrest", - artifact = "org.hamcrest:hamcrest:2.2", - sha1 = "1820c0968dba3a11a1b30669bb1f01978a91dedc", -) - -maven_jar( - name = "mockito", - artifact = "org.mockito:mockito-core:5.14.2", - sha1 = "f7bf936008d7664e2002c3faf0c02071c8d10e7c", -) - -maven_jar( - name = "assertj-core", - artifact = "org.assertj:assertj-core:3.27.0", - sha1 = "a04bf3feaf3dc6ede0770c160a7dc1c214f1a2c9", -) - -BYTE_BUDDY_VERSION = "1.15.11" - -maven_jar( - name = "bytebuddy", - artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, - sha1 = "f61886478e0f9ee4c21d09574736f0ff45e0a46c", -) - -maven_jar( - name = "bytebuddy-agent", - artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, - sha1 = "a38b16385e867f59a641330f0362ebe742788ed8", -) - -maven_jar( - name = "objenesis", - artifact = "org.objenesis:objenesis:3.4", - sha1 = "675cbe121a68019235d27f6c34b4f0ac30e07418", -) - -maven_jar( - name = "gson", - artifact = "com.google.code.gson:gson:2.11.0", - sha1 = "527175ca6d81050b53bdd4c457a6d6e017626b0e", -) - -JETTY_VER = "12.0.16" - -maven_jar( - name = "jetty-servlet", - artifact = "org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VER, - sha1 = "022a746c00b1ac5c790fee65a398c707160a46d8", -) - -maven_jar( - name = "jetty-security", - artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER, - sha1 = "23b1a3abecf9d6f5498064a32d9145ae1d8330f9", -) - -maven_jar( - name = "jetty-server", - artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER, - sha1 = "3e3638b4bfbee04c27b3ae68e4949fc43b40a042", -) - -maven_jar( - name = "jetty-session", - artifact = "org.eclipse.jetty:jetty-session:" + JETTY_VER, - sha1 = "79cdedc7afebbdba4453f603dfe2f970baa35cc3", -) - -maven_jar( - name = "jetty-http", - artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER, - sha1 = "68019fa90e8420ae15c109bd8c8611cacbaf43e5", -) - -maven_jar( - name = "jetty-io", - artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER, - sha1 = "7a162c537a99bbaf35a074fec9a50815e6c81d9d", -) - -maven_jar( - name = "jetty-util", - artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER, - sha1 = "e262e505363e5925df15618622d9888aefc1b0d0", -) - -maven_jar( - name = "jetty-util-ajax", - artifact = "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VER, - sha1 = "60225034131e3f771b40bc75c15bd9cc4952302b", -) - -BOUNCYCASTLE_VER = "1.79" - -maven_jar( - name = "bcpg", - artifact = "org.bouncycastle:bcpg-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "904dd8a8e1c9f7d58d1ffa7f4ca3fb00736a601f", - src_sha1 = "9e372826141edb213d5921131ee68dc276dc99ef", -) - -maven_jar( - name = "bcprov", - artifact = "org.bouncycastle:bcprov-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "4d8e2732bcee15f1db93df266c3f5b70ce5cac21", - src_sha1 = "8647816d667ee526a8e3a456229ac5f9f96d2315", -) - -maven_jar( - name = "bcutil", - artifact = "org.bouncycastle:bcutil-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "ecfc5aef97cc7676ea0de5c53c407b9f533f0ad5", - src_sha1 = "00df03977fb0b80395da655623abca9d7d7dcb66", -) - -maven_jar( - name = "bcpkix", - artifact = "org.bouncycastle:bcpkix-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "7693cec3b8779b74b35466dcaeeaac7409872954", - src_sha1 = "57a60d1d9f75320eef70a095dfae679d97ade1c2", -) +# This file marks the root of the Bazel workspace. +# See MODULE.bazel for external dependencies setup. @@ -6,7 +6,7 @@ java_library( "//org.eclipse.jgit.pgm:__pkg__", "//org.eclipse.jgit.pgm.test:__pkg__", ], - exports = ["@args4j//jar"], + exports = ["@jgit_deps//:args4j_args4j"], ) java_library( @@ -16,7 +16,7 @@ java_library( "//org.eclipse.jgit.pgm.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@commons-compress//jar"], + exports = ["@jgit_deps//:org_apache_commons_commons_compress"], ) java_library( @@ -26,7 +26,7 @@ java_library( "//org.eclipse.jgit.pgm.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@commons-lang3//jar"], + exports = ["@jgit_deps//:org_apache_commons_commons_lang3"], ) java_library( @@ -36,7 +36,7 @@ java_library( "//org.eclipse.jgit.pgm.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@commons-io//jar"], + exports = ["@jgit_deps//:commons_io_commons_io"], ) java_library( @@ -45,23 +45,13 @@ java_library( "//org.eclipse.jgit:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@commons-codec//jar"], + exports = ["@jgit_deps//:commons_codec_commons_codec"], ) java_library( name = "commons-logging", visibility = ["//visibility:public"], - exports = ["@commons-logging//jar"], -) - -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"], + exports = ["@jgit_deps//:commons_logging_commons_logging"], ) java_library( @@ -70,7 +60,7 @@ java_library( "//org.eclipse.jgit.lfs:__pkg__", "//org.eclipse.jgit.lfs.server:__pkg__", ], - exports = ["@gson//jar"], + exports = ["@jgit_deps//:com_google_code_gson_gson"], ) java_library( @@ -80,7 +70,7 @@ java_library( "//org.eclipse.jgit.lfs.server.test:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", ], - exports = ["@httpclient//jar"], + exports = ["@jgit_deps//:org_apache_httpcomponents_httpclient"], ) java_library( @@ -92,7 +82,7 @@ java_library( "//org.eclipse.jgit.lfs.server.test:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", ], - exports = ["@httpcore//jar"], + exports = ["@jgit_deps//:org_apache_httpcomponents_httpcore"], ) java_library( @@ -104,7 +94,7 @@ java_library( "//org.eclipse.jgit.ssh.apache.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@sshd-osgi//jar"], + exports = ["@jgit_deps//:org_apache_sshd_sshd_osgi"], ) java_library( @@ -115,7 +105,7 @@ java_library( "//org.eclipse.jgit.ssh.apache.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@sshd-sftp//jar"], + exports = ["@jgit_deps//:org_apache_sshd_sshd_sftp"], ) java_library( @@ -123,7 +113,7 @@ java_library( visibility = [ "//org.eclipse.jgit.ssh.apache.agent:__pkg__", ], - exports = ["@jna//jar"], + exports = ["@jgit_deps//:net_java_dev_jna_jna"], ) java_library( @@ -131,20 +121,20 @@ java_library( visibility = [ "//org.eclipse.jgit.ssh.apache.agent:__pkg__", ], - exports = ["@jna-platform//jar"], + exports = ["@jgit_deps//:net_java_dev_jna_jna_platform"], ) java_library( name = "javaewah", visibility = ["//visibility:public"], - exports = ["@javaewah//jar"], + exports = ["@jgit_deps//:com_googlecode_javaewah_JavaEWAH"], ) java_library( name = "jetty-http", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@jetty-http//jar"], + exports = ["@jgit_deps//:org_eclipse_jetty_jetty_http"], runtime_deps = [":commons-codec"], ) @@ -152,28 +142,28 @@ java_library( name = "jetty-io", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@jetty-io//jar"], + exports = ["@jgit_deps//:org_eclipse_jetty_jetty_io"], ) java_library( name = "jetty-security", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@jetty-security//jar"], + exports = ["@jgit_deps//:org_eclipse_jetty_jetty_security"], ) java_library( name = "jetty-session", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@jetty-session//jar"], + exports = ["@jgit_deps//:org_eclipse_jetty_jetty_session"], ) java_library( name = "jetty-server", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@jetty-server//jar"], + exports = ["@jgit_deps//:org_eclipse_jetty_jetty_server"], ) java_library( @@ -181,8 +171,8 @@ java_library( # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], exports = [ - "@jetty-servlet//jar", - "@jetty-util-ajax//jar", + "@jgit_deps//:org_eclipse_jetty_ee10_jetty_ee10_servlet", + "@jgit_deps//:org_eclipse_jetty_jetty_util_ajax", ], ) @@ -190,7 +180,7 @@ java_library( name = "jetty-util", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@jetty-util//jar"], + exports = ["@jgit_deps//:org_eclipse_jetty_jetty_util"], ) java_library( @@ -200,7 +190,7 @@ java_library( "//org.eclipse.jgit.ssh.jsch:__pkg__", "//org.eclipse.jgit.ssh.jsch.test:__pkg__", ], - exports = ["@jsch//jar"], + exports = ["@jgit_deps//:com_jcraft_jsch"], ) java_library( @@ -208,9 +198,11 @@ java_library( visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", "//org.eclipse.jgit.gpg.bc.test:__pkg__", + "//org.eclipse.jgit.ssh.apache:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@bcpg//jar"], + exports = ["@jgit_deps//:org_bouncycastle_bcpg_jdk18on"], ) java_library( @@ -218,9 +210,12 @@ java_library( visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", "//org.eclipse.jgit.gpg.bc.test:__pkg__", + "//org.eclipse.jgit.ssh.apache:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", + "//org.eclipse.jgit.ssh.jsch.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@bcprov//jar"], + exports = ["@jgit_deps//:org_bouncycastle_bcprov_jdk18on"], ) java_library( @@ -228,18 +223,24 @@ java_library( visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", "//org.eclipse.jgit.gpg.bc.test:__pkg__", + "//org.eclipse.jgit.ssh.apache:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", + "//org.eclipse.jgit.ssh.jsch.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@bcutil//jar"], + exports = ["@jgit_deps//:org_bouncycastle_bcutil_jdk18on"], ) java_library( name = "bcpkix", visibility = [ "//org.eclipse.jgit.gpg.bc:__pkg__", + "//org.eclipse.jgit.ssh.apache:__pkg__", + "//org.eclipse.jgit.ssh.apache.test:__pkg__", + "//org.eclipse.jgit.ssh.jsch.test:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@bcpkix//jar"], + exports = ["@jgit_deps//:org_bouncycastle_bcpkix_jdk18on"], ) java_library( @@ -248,7 +249,7 @@ java_library( "//org.eclipse.jgit.ssh.jsch:__pkg__", "//org.eclipse.jgit.test:__pkg__", ], - exports = ["@jzlib//jar"], + exports = ["@jgit_deps//:com_jcraft_jzlib"], ) java_library( @@ -256,12 +257,12 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ - "@bytebuddy-agent//jar", - "@bytebuddy//jar", - "@hamcrest//jar", - "@junit//jar", - "@mockito//jar", - "@objenesis//jar", + "@jgit_deps//:net_bytebuddy_byte_buddy_agent", + "@jgit_deps//:net_bytebuddy_byte_buddy", + "@jgit_deps//:org_hamcrest_hamcrest", + "@jgit_deps//:junit_junit", + "@jgit_deps//:org_mockito_mockito_core", + "@jgit_deps//:org_objenesis_objenesis", ], ) @@ -270,10 +271,10 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ - "@bytebuddy-agent//jar", - "@bytebuddy//jar", - "@mockito//jar", - "@objenesis//jar", + "@jgit_deps//:net_bytebuddy_byte_buddy_agent", + "@jgit_deps//:net_bytebuddy_byte_buddy", + "@jgit_deps//:org_mockito_mockito_core", + "@jgit_deps//:org_objenesis_objenesis", ], ) @@ -282,7 +283,7 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ - "@assertj-core//jar", + "@jgit_deps//:org_assertj_assertj_core", ], ) @@ -297,24 +298,24 @@ java_library( "//org.eclipse.jgit.lfs.server.test:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", ], - exports = ["@servlet-api//jar"], + exports = ["@jgit_deps//:jakarta_servlet_jakarta_servlet_api_6_1_0"], ) java_library( name = "slf4j-api", visibility = ["//visibility:public"], - exports = ["@log-api//jar"], + exports = ["@jgit_deps//:org_slf4j_slf4j_api"], ) java_library( name = "slf4j-simple", visibility = ["//visibility:public"], - exports = ["@slf4j-simple//jar"], + exports = ["@jgit_deps//:org_slf4j_slf4j_simple"], ) java_library( name = "xz", testonly = 1, visibility = ["//visibility:public"], - exports = ["@tukaani-xz//jar"], + exports = ["@jgit_deps//:org_tukaani_xz"], ) diff --git a/lib/jmh/BUILD b/lib/jmh/BUILD index b15e66c2b9..1bba1a5cb1 100644 --- a/lib/jmh/BUILD +++ b/lib/jmh/BUILD @@ -4,9 +4,9 @@ java_library( name = "jmh", visibility = ["//visibility:public"], exports = [ - "@jmh-annotations//jar", - "@jmh-core//jar", - "@jopt//jar", - "@math3//jar", + "@jgit_deps//:org_openjdk_jmh_jmh_generator_annprocess", + "@jgit_deps//:org_openjdk_jmh_jmh_core", + "@jgit_deps//:net_sf_jopt_simple_jopt_simple", + "@jgit_deps//:org_apache_commons_commons_math3", ], ) diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index 0069b09467..c32a912035 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF @@ -5,13 +5,13 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ant.test Bundle-SymbolicName: org.eclipse.jgit.ant.test Bundle-Vendor: %Bundle-Vendor -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.ant.tasks;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.ant.tasks;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 c6c81648ae..56e234ae63 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.2.0-SNAPSHOT</version> + <version>7.4.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 3af82e4759..139ce8ea06 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF @@ -3,13 +3,13 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ant Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)" + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)" Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.ant;version="7.2.0", - org.eclipse.jgit.ant.tasks;version="7.2.0"; +Export-Package: org.eclipse.jgit.ant;version="7.4.0", + org.eclipse.jgit.ant.tasks;version="7.4.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 89d05be73b..b503bb4039 100644 --- a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ant - Sources Bundle-SymbolicName: org.eclipse.jgit.ant.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ant;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ant;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index 11806f15c6..5c5e14bdaa 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ant</artifactId> diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF index b142a66a8c..badb0f20eb 100644 --- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.archive Bundle-SymbolicName: org.eclipse.jgit.archive -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -13,18 +13,18 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.4,2.0)", org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)", org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)", org.apache.commons.compress.compressors.xz;version="[1.4,2.0)", - org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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.2.0"; +Export-Package: org.eclipse.jgit.archive;version="7.4.0"; uses:="org.apache.commons.compress.archivers, org.osgi.framework, org.eclipse.jgit.api, org.eclipse.jgit.lib", - org.eclipse.jgit.archive.internal;version="7.2.0";x-internal:=true + org.eclipse.jgit.archive.internal;version="7.4.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 3ca6590f02..df4f8d0e2c 100644 --- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.archive - Sources Bundle-SymbolicName: org.eclipse.jgit.archive.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.archive;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.archive;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml index 27a2bba5a2..6b4e810d59 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.archive</artifactId> diff --git a/org.eclipse.jgit.benchmarks/BUILD b/org.eclipse.jgit.benchmarks/BUILD index 6198e4d0c7..7c311e7994 100644 --- a/org.eclipse.jgit.benchmarks/BUILD +++ b/org.eclipse.jgit.benchmarks/BUILD @@ -10,6 +10,7 @@ jmh_java_benchmarks( testonly = 1, deps = [ "//lib:javaewah", + "//lib:junit", "//lib:slf4j-api", "//org.eclipse.jgit:jgit", "//org.eclipse.jgit.junit:junit", diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml index 3079742c79..da20ef4f33 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.2.0-SNAPSHOT</version> + <version>7.4.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 52a881bd11..44e862e7c8 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 java.util.stream.IntStream; 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.revwalk.RevWalk; 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 class GetRefsBenchmark { @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 class GetRefsBenchmark { @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 class GetRefsBenchmark { ((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 class GetRefsBenchmark { 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 class GetRefsBenchmark { @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 class GetRefsBenchmark { @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.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml index 9493c07dbc..58a9e41fe8 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.2.0-SNAPSHOT</version> + <version>7.4.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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ant</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.archive</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.apache</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.server</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.server</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ui</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ssh.apache</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ant.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.server.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.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 35294256e1..6e26c9d8b9 100644 --- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF @@ -3,20 +3,20 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.gpg.bc.test Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.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.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.2.0,7.3.0)", - org.eclipse.jgit.gpg.bc.internal.keys;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.sha1;version="[7.2.0,7.3.0)", +Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.80.0,2.0.0)", + org.bouncycastle.jce.provider;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.80.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.80.0,2.0.0)", + org.eclipse.jgit.gpg.bc.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.gpg.bc.internal.keys;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.sha1;version="[7.4.0,7.5.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 245ba7e127..cfa732a2e2 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.gpg.bc.test</artifactId> diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF index 2120439e51..cb32155513 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF @@ -3,28 +3,28 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.gpg.bc Bundle-SymbolicName: org.eclipse.jgit.gpg.bc;singleton:=true -Fragment-Host: org.eclipse.jgit;bundle-version="[7.2.0,7.3.0)" +Fragment-Host: org.eclipse.jgit;bundle-version="[7.4.0,7.5.0)" Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/gpg_bc -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -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)", +Import-Package: org.bouncycastle.asn1;version="[1.80.0,2.0.0)", + org.bouncycastle.asn1.x9;version="[1.80.0,2.0.0)", + org.bouncycastle.bcpg;version="[1.80.0,2.0.0)", + org.bouncycastle.bcpg.sig;version="[1.80.0,2.0.0)", + org.bouncycastle.crypto.ec;version="[1.80.0,2.0.0)", + org.bouncycastle.gpg;version="[1.80.0,2.0.0)", + org.bouncycastle.gpg.keybox;version="[1.80.0,2.0.0)", + org.bouncycastle.gpg.keybox.jcajce;version="[1.80.0,2.0.0)", + org.bouncycastle.jcajce.interfaces;version="[1.80.0,2.0.0)", + org.bouncycastle.jcajce.util;version="[1.80.0,2.0.0)", + org.bouncycastle.math.ec;version="[1.80.0,2.0.0)", + org.bouncycastle.math.field;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp.jcajce;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.80.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.80.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.80.0,2.0.0)", org.slf4j;version="[1.7.0,3.0.0)" -Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.2.0";x-friends:="org.eclipse.jgit.gpg.bc.test", - org.eclipse.jgit.gpg.bc.internal.keys;version="7.2.0";x-friends:="org.eclipse.jgit.gpg.bc.test" +Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.4.0";x-friends:="org.eclipse.jgit.gpg.bc.test", + org.eclipse.jgit.gpg.bc.internal.keys;version="7.4.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 532e749cb2..256f893ea4 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.gpg.bc - Sources Bundle-SymbolicName: org.eclipse.jgit.gpg.bc.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml index f94e2b27b1..fe15d9892d 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.gpg.bc</artifactId> diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF index 7d23d53614..ff35e6f960 100644 --- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.apache Bundle-SymbolicName: org.eclipse.jgit.http.apache -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor @@ -26,11 +26,11 @@ Import-Package: javax.net.ssl, 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.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)" -Export-Package: org.eclipse.jgit.transport.http.apache;version="7.2.0"; + org.eclipse.jgit.annotations;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)" +Export-Package: org.eclipse.jgit.transport.http.apache;version="7.4.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 679252de34..807bb1868a 100644 --- a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.http.apache - Sources Bundle-SymbolicName: org.eclipse.jgit.http.apache.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml index c390d8f5ee..d6d294bc02 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.apache</artifactId> diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index 39dc2ef42a..d67e255e19 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-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.server Bundle-SymbolicName: org.eclipse.jgit.http.server -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.http.server;version="7.2.0", - org.eclipse.jgit.http.server.glue;version="7.2.0"; +Export-Package: org.eclipse.jgit.http.server;version="7.4.0", + org.eclipse.jgit.http.server.glue;version="7.4.0"; uses:="jakarta.servlet, jakarta.servlet.http", - org.eclipse.jgit.http.server.resolver;version="7.2.0"; + org.eclipse.jgit.http.server.resolver;version="7.4.0"; uses:="jakarta.servlet.http org.eclipse.jgit.transport.resolver, org.eclipse.jgit.lib, @@ -19,14 +19,14 @@ Bundle-ActivationPolicy: lazy 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.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.parser;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.resolver;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)" + org.eclipse.jgit.annotations;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.parser;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.resolver;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 e7940bd358..b9f500fd02 100644 --- a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.http.server - Sources Bundle-SymbolicName: org.eclipse.jgit.http.server.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index 3f79f8b82d..3252d7ea92 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.server</artifactId> diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index 3550501dba..49ab1caadb 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.test Bundle-SymbolicName: org.eclipse.jgit.http.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -29,26 +29,26 @@ Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", 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.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.http.server;version="[7.2.0,7.3.0)", - org.eclipse.jgit.http.server.glue;version="[7.2.0,7.3.0)", - org.eclipse.jgit.http.server.resolver;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http.apache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.resolver;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.http.server;version="[7.4.0,7.5.0)", + org.eclipse.jgit.http.server.glue;version="[7.4.0,7.5.0)", + org.eclipse.jgit.http.server.resolver;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http.apache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.resolver;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 2f25191fee..9500978896 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.2.0-SNAPSHOT</version> + <version>7.4.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 850e895790..b0d17adb3a 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 class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { 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/BUILD b/org.eclipse.jgit.junit.http/BUILD index 5ddd0c8d56..66620cea51 100644 --- a/org.eclipse.jgit.junit.http/BUILD +++ b/org.eclipse.jgit.junit.http/BUILD @@ -6,7 +6,7 @@ java_library( name = "junit-http", testonly = 1, srcs = glob(["src/**/*.java"]), - resources = glob(["resources/**"]), + resources = glob(["resources/**"], allow_empty=True), # TODO(davido): we want here provided deps deps = [ "//lib:jetty-http", diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index 4ba595901b..7a5a02640d 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit.http Bundle-SymbolicName: org.eclipse.jgit.junit.http -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy @@ -22,17 +22,17 @@ Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", 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.2.0,7.3.0)", - org.eclipse.jgit.http.server;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.resolver;version="[7.2.0,7.3.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.http.server;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.resolver;version="[7.4.0,7.5.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.2.0"; +Export-Package: org.eclipse.jgit.junit.http;version="7.4.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 5abd7d6d51..a9ba3992f0 100644 --- a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.junit.http - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.http.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index ea38ae31ba..9f405f350c 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.2.0-SNAPSHOT</version> + <version>7.4.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 bcd9fbfc81..6775b6fb24 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-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit.ssh Bundle-SymbolicName: org.eclipse.jgit.junit.ssh -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.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.14.0,2.15.0)", - org.apache.sshd.common.config.keys;version="[2.14.0,2.15.0)", - org.apache.sshd.common.file.virtualfs;version="[2.14.0,2.15.0)", - org.apache.sshd.common.helpers;version="[2.14.0,2.15.0)", - org.apache.sshd.common.io;version="[2.14.0,2.15.0)", - org.apache.sshd.common.kex;version="[2.14.0,2.15.0)", - org.apache.sshd.common.keyprovider;version="[2.14.0,2.15.0)", - org.apache.sshd.common.session;version="[2.14.0,2.15.0)", - org.apache.sshd.common.signature;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.buffer;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.logging;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.security;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.threads;version="[2.14.0,2.15.0)", - org.apache.sshd.core;version="[2.14.0,2.15.0)", - org.apache.sshd.server;version="[2.14.0,2.15.0)", - org.apache.sshd.server.auth;version="[2.14.0,2.15.0)", - org.apache.sshd.server.auth.gss;version="[2.14.0,2.15.0)", - org.apache.sshd.server.auth.keyboard;version="[2.14.0,2.15.0)", - org.apache.sshd.server.auth.password;version="[2.14.0,2.15.0)", - org.apache.sshd.server.command;version="[2.14.0,2.15.0)", - org.apache.sshd.server.session;version="[2.14.0,2.15.0)", - org.apache.sshd.server.shell;version="[2.14.0,2.15.0)", - org.apache.sshd.server.subsystem;version="[2.14.0,2.15.0)", - org.apache.sshd.sftp;version="[2.14.0,2.15.0)", - org.apache.sshd.sftp.server;version="[2.14.0,2.15.0)", - org.eclipse.jgit.annotations;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.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.4.0,7.5.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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.2.0" +Export-Package: org.eclipse.jgit.junit.ssh;version="7.4.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 b8f22cea5d..a01cf267ae 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.junit.ssh - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.ssh.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml index f937748212..da5920b5e2 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.2.0-SNAPSHOT</version> + <version>7.4.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 0000000000..27815301c2 --- /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/BUILD b/org.eclipse.jgit.junit/BUILD index 623c5beb2d..f4a7165dbb 100644 --- a/org.eclipse.jgit.junit/BUILD +++ b/org.eclipse.jgit.junit/BUILD @@ -7,7 +7,7 @@ java_library( testonly = 1, srcs = glob(["src/**/*.java"]), resource_strip_prefix = "org.eclipse.jgit.junit/resources", - resources = glob(["resources/**"]), + resources = glob(["resources/**"], allow_empty=True), deps = [ "//lib:junit", # We want these deps to be provided_deps diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF index 6488a887fb..92371aec69 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF @@ -3,36 +3,36 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.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.2.0,7.3.0)", - org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.dircache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.merge;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="7.2.0", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.io;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.time;version="[7.2.0,7.3.0)", +Import-Package: org.eclipse.jgit.annotations;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.dircache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.merge;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="7.4.0", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.io;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.time;version="[7.4.0,7.5.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.2.0"; +Export-Package: org.eclipse.jgit.junit;version="7.4.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -45,4 +45,4 @@ Export-Package: org.eclipse.jgit.junit;version="7.2.0"; org.junit.runners.model, org.junit.runner, org.eclipse.jgit.util.time", - org.eclipse.jgit.junit.time;version="7.2.0";uses:="org.eclipse.jgit.util.time" + org.eclipse.jgit.junit.time;version="7.4.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 9d494cb2e0..5b1590816a 100644 --- a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.junit - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index 9f43ced73b..f50b9d8aa2 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.2.0-SNAPSHOT</version> + <version>7.4.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 0000000000..eb23bec584 --- /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 c15fc9921e..0d20f6488a 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 @@ -26,14 +26,13 @@ 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; @@ -48,6 +47,7 @@ import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; import org.junit.Rule; +import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; /** @@ -85,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; @@ -115,11 +125,8 @@ public abstract class LocalDiskRepositoryTestCase { */ @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); @@ -220,12 +227,6 @@ public abstract class LocalDiskRepositoryTestCase { System.gc(); } FS.DETECTED.setUserHome(homeDir); - if (tmp != null) { - recursiveDelete(tmp, false, true); - } - if (tmp != null && !tmp.exists()) { - Cleanup.removed(tmp); - } SystemReader.setInstance(null); } @@ -624,41 +625,4 @@ public abstract class LocalDiskRepositoryTestCase { 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/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index 706930a50f..2d00a850e5 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 @@ -159,8 +159,8 @@ public class TestRepository<R extends Repository> implements AutoCloseable { 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); } @@ -201,7 +201,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * @since 4.2 * @deprecated Use {@link #getInstant()} instead. */ - @Deprecated + @Deprecated(since = "7.2") public Date getDate() { return new Date(mockSystemReader.getCurrentTime()); } @@ -222,7 +222,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * @return timezone used for default identities. * @deprecated Use {@link #getTimeZoneId()} instead. */ - @Deprecated + @Deprecated(since = "7.2") public TimeZone getTimeZone() { return mockSystemReader.getTimeZone(); } 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 77749c8d89..414cec87ed 100644 --- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.server.test Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -26,24 +26,24 @@ Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", 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.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.server;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.server.fs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.test;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.server;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.server.fs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.test;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 98e63b0f1e..5c4b27f857 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.2.0-SNAPSHOT</version> + <version>7.4.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 1973b26477..019c6ec849 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF @@ -3,19 +3,19 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.server Bundle-SymbolicName: org.eclipse.jgit.lfs.server -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.lfs.server;version="7.2.0"; +Export-Package: org.eclipse.jgit.lfs.server;version="7.4.0"; uses:="jakarta.servlet.http, org.eclipse.jgit.lfs.lib", - org.eclipse.jgit.lfs.server.fs;version="7.2.0"; + org.eclipse.jgit.lfs.server.fs;version="7.4.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.2.0";x-internal:=true, - org.eclipse.jgit.lfs.server.s3;version="7.2.0"; + org.eclipse.jgit.lfs.server.internal;version="7.4.0";x-internal:=true, + org.eclipse.jgit.lfs.server.s3;version="7.4.0"; uses:="org.eclipse.jgit.lfs.server, org.eclipse.jgit.lfs.lib" Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -24,15 +24,15 @@ Import-Package: com.google.gson;version="[2.8.0,3.0.0)", 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.2.0,7.3.0)", - org.eclipse.jgit.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http.apache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.annotations;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http.apache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 73f5cab59d..82103de270 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.lfs.server - Sources Bundle-SymbolicName: org.eclipse.jgit.lfs.server.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml index 0dd0786050..392fe172dc 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.2.0-SNAPSHOT</version> + <version>7.4.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 f27377447c..bbd5dd2f88 100644 --- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF @@ -3,28 +3,28 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.test Bundle-SymbolicName: org.eclipse.jgit.lfs.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.attributes;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", +Import-Package: org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.attributes;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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.2.0";x-friends:="org.eclipse.jgit.lfs.server.test" +Export-Package: org.eclipse.jgit.lfs.test;version="7.4.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 eff7e0b7eb..01a0c29ab8 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.test</artifactId> diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF index fb211cc89c..e7f31773d7 100644 --- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF @@ -3,32 +3,32 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs Bundle-SymbolicName: org.eclipse.jgit.lfs -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.lfs;version="7.2.0", - org.eclipse.jgit.lfs.errors;version="7.2.0", - org.eclipse.jgit.lfs.internal;version="7.2.0";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server", - org.eclipse.jgit.lfs.lib;version="7.2.0" +Export-Package: org.eclipse.jgit.lfs;version="7.4.0", + org.eclipse.jgit.lfs.errors;version="7.4.0", + org.eclipse.jgit.lfs.internal;version="7.4.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.4.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.2.0,7.3.0)";resolution:=optional, - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.attributes;version="[7.2.0,7.3.0)", - org.eclipse.jgit.diff;version="[7.2.0,7.3.0)", - org.eclipse.jgit.dircache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.hooks;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.pack;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.io;version="[7.2.0,7.3.0)" + org.eclipse.jgit.annotations;version="[7.4.0,7.5.0)";resolution:=optional, + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.attributes;version="[7.4.0,7.5.0)", + org.eclipse.jgit.diff;version="[7.4.0,7.5.0)", + org.eclipse.jgit.dircache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.hooks;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.pack;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.io;version="[7.4.0,7.5.0)" diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF index 4ca03a3f72..b1ea912859 100644 --- a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.lfs - Sources Bundle-SymbolicName: org.eclipse.jgit.lfs.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml index 329740085e..28aa4ea7a2 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs</artifactId> 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 43980f06ae..7cda565235 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.2.0.qualifier" + version="7.4.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 59345e75f9..7a4331c37e 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.2.0-SNAPSHOT</version> + <version>7.4.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 ae91bd5405..7f67dc305b 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.4.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 aa88700423..cf06407d1a 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.2.0-SNAPSHOT</version> + <version>7.4.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 57d7d8dd69..97abb2d186 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.4.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 2038cfd58c..40738e38a2 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.2.0-SNAPSHOT</version> + <version>7.4.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 d9a9db307d..79cd1ba8bf 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.4.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 d98990c532..9f8496426f 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.2.0-SNAPSHOT</version> + <version>7.4.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 8f0c532a4a..5c324bd11e 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.4.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 7e1b0c8226..1aef24e1d6 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.2.0-SNAPSHOT</version> + <version>7.4.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 78867c96c0..330ed6eaa5 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> - <import feature="org.eclipse.jgit.lfs" version="7.2.0" match="equivalent"/> - <import feature="org.eclipse.jgit.ssh.apache" version="7.2.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.4.0" match="equivalent"/> + <import feature="org.eclipse.jgit.lfs" version="7.4.0" match="equivalent"/> + <import feature="org.eclipse.jgit.ssh.apache" version="7.4.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 02435b6c08..f0fbe45391 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.2.0-SNAPSHOT</version> + <version>7.4.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 de5477203e..eef699cfa1 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> 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 d3773f54f3..23c7bd1082 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.2.0-SNAPSHOT</version> + <version>7.4.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 b8f402e4f0..aa384a0389 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.4.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 4eee8255cc..af577afa8c 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.2.0-SNAPSHOT</version> + <version>7.4.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.2.0-SNAPSHOT</version> + <version>7.4.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 811beafca6..14d12273aa 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import feature="org.eclipse.jgit" version="7.4.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 025844c6b0..4024b2955e 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.2.0-SNAPSHOT</version> + <version>7.4.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 a0cd57bcbb..a4a005de9b 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.2.0.qualifier" + version="7.4.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.2.0" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="7.4.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 81c9651fd9..679fea17a6 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> 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 index ff4f0262f1..cbed9191c5 100644 --- 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 @@ -1,15 +1,13 @@ <?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="1734684337"> +<target name="jgit-4.32" sequenceNumber="1749854000"> <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"/> @@ -63,13 +61,13 @@ <dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-osgi</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <type>jar</type> </dependency> <dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-sftp</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <type>jar</type> </dependency> </dependencies> @@ -79,7 +77,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.2</version> + <version>5.18.0</version> <type>jar</type> </dependency> </dependencies> @@ -89,13 +87,13 @@ <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> - <version>5.15.0</version> + <version>5.17.0</version> <type>jar</type> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> - <version>5.15.0</version> + <version>5.17.0</version> <type>jar</type> </dependency> </dependencies> @@ -105,49 +103,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> @@ -183,7 +181,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>2.11.0</version> + <version>2.13.1</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +191,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.11</version> + <version>1.17.5</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.11</version> + <version>1.17.5</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +207,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> </dependencies> @@ -237,7 +235,7 @@ <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> - <version>3.27.0</version> + <version>3.27.3</version> <type>jar</type> </dependency> </dependencies> @@ -257,7 +255,7 @@ <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> - <version>1.17.1</version> + <version>1.18.0</version> <type>jar</type> </dependency> <dependency> @@ -275,13 +273,13 @@ <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <version>2.18.0</version> + <version>2.19.0</version> <type>jar</type> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> - <version>1.3.4</version> + <version>1.3.5</version> <type>jar</type> </dependency> </dependencies> 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 index a94fc6c9d4..1a8648a78c 100644 --- 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 @@ -1,15 +1,13 @@ <?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="1734684337"> +<target name="jgit-4.33" sequenceNumber="1749854000"> <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"/> @@ -63,13 +61,13 @@ <dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-osgi</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <type>jar</type> </dependency> <dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-sftp</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <type>jar</type> </dependency> </dependencies> @@ -79,7 +77,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.2</version> + <version>5.18.0</version> <type>jar</type> </dependency> </dependencies> @@ -89,13 +87,13 @@ <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> - <version>5.15.0</version> + <version>5.17.0</version> <type>jar</type> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> - <version>5.15.0</version> + <version>5.17.0</version> <type>jar</type> </dependency> </dependencies> @@ -105,49 +103,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> @@ -183,7 +181,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>2.11.0</version> + <version>2.13.1</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +191,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.11</version> + <version>1.17.5</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.11</version> + <version>1.17.5</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +207,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> </dependencies> @@ -237,7 +235,7 @@ <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> - <version>3.27.0</version> + <version>3.27.3</version> <type>jar</type> </dependency> </dependencies> @@ -257,7 +255,7 @@ <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> - <version>1.17.1</version> + <version>1.18.0</version> <type>jar</type> </dependency> <dependency> @@ -275,13 +273,13 @@ <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <version>2.18.0</version> + <version>2.19.0</version> <type>jar</type> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> - <version>1.3.4</version> + <version>1.3.5</version> <type>jar</type> </dependency> </dependencies> 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 index c67117ea45..0d636aaae8 100644 --- 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 @@ -1,15 +1,13 @@ <?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="1734684337"> +<target name="jgit-4.34" sequenceNumber="1749854000"> <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.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"/> @@ -63,13 +61,13 @@ <dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-osgi</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <type>jar</type> </dependency> <dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-sftp</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <type>jar</type> </dependency> </dependencies> @@ -79,7 +77,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.2</version> + <version>5.18.0</version> <type>jar</type> </dependency> </dependencies> @@ -89,13 +87,13 @@ <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> - <version>5.15.0</version> + <version>5.17.0</version> <type>jar</type> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> - <version>5.15.0</version> + <version>5.17.0</version> <type>jar</type> </dependency> </dependencies> @@ -105,49 +103,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.0.16</version> + <version>12.0.22</version> <type>jar</type> </dependency> <dependency> @@ -183,7 +181,7 @@ <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> - <version>2.11.0</version> + <version>2.13.1</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +191,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.11</version> + <version>1.17.5</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.11</version> + <version>1.17.5</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +207,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.79</version> + <version>1.81</version> <type>jar</type> </dependency> </dependencies> @@ -237,7 +235,7 @@ <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> - <version>3.27.0</version> + <version>3.27.3</version> <type>jar</type> </dependency> </dependencies> @@ -257,7 +255,7 @@ <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> - <version>1.17.1</version> + <version>1.18.0</version> <type>jar</type> </dependency> <dependency> @@ -275,13 +273,13 @@ <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <version>2.18.0</version> + <version>2.19.0</version> <type>jar</type> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> - <version>1.3.4</version> + <version>1.3.5</version> <type>jar</type> </dependency> </dependencies> 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 0000000000..c270c0978c --- /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="1749854000"> + <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.18.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.17.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <version>5.17.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.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-session</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>12.0.22</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.13.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.5</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>1.17.5</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.81</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk18on</artifactId> + <version>1.81</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.81</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcutil-jdk18on</artifactId> + <version>1.81</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.19.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 0000000000..3c0646eb46 --- /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/jgit-4.36.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target new file mode 100644 index 0000000000..8c22b66b5d --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.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.36" sequenceNumber="1749854000"> + <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-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/2025-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.18.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.17.0</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna-platform</artifactId> + <version>5.17.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.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-io</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-session</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>12.0.22</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util-ajax</artifactId> + <version>12.0.22</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.13.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.5</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>1.17.5</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.81</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk18on</artifactId> + <version>1.81</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk18on</artifactId> + <version>1.81</version> + <type>jar</type> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcutil-jdk18on</artifactId> + <version>1.81</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.19.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.36.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.tpd new file mode 100644 index 0000000000..053929fb8f --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.tpd @@ -0,0 +1,8 @@ +target "jgit-4.36" with source configurePhase + +include "orbit/orbit-4.36.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/staging/2025-06/" { + 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 bbea833864..b2282796e4 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,7 +10,7 @@ maven apache dependency { groupId = "commons-codec" artifactId = "commons-codec" - version = "1.17.1" + version = "1.18.0" } dependency { groupId = "org.apache.commons" @@ -25,12 +25,12 @@ maven apache dependency { groupId = "commons-io" artifactId = "commons-io" - version = "2.18.0" + version = "2.19.0" } dependency { groupId = "commons-logging" artifactId = "commons-logging" - version = "1.3.4" + version = "1.3.5" } } @@ -56,7 +56,7 @@ maven assertj dependency { groupId = "org.assertj" artifactId = "assertj-core" - version = "3.27.0" + version = "3.27.3" } } @@ -69,22 +69,22 @@ maven bouncycastle dependency { groupId = "org.bouncycastle" artifactId = "bcpg-jdk18on" - version = "1.79" + version = "1.81" } dependency { groupId = "org.bouncycastle" artifactId = "bcprov-jdk18on" - version = "1.79" + version = "1.81" } dependency { groupId = "org.bouncycastle" artifactId = "bcpkix-jdk18on" - version = "1.79" + version = "1.81" } dependency { groupId = "org.bouncycastle" artifactId = "bcutil-jdk18on" - version = "1.79" + version = "1.81" } } @@ -97,12 +97,12 @@ maven bytebuddy dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy" - version = "1.15.11" + version = "1.17.5" } dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy-agent" - version = "1.15.11" + version = "1.17.5" } } @@ -115,7 +115,7 @@ maven gson dependency { groupId = "com.google.code.gson" artifactId = "gson" - version = "2.11.0" + version = "2.13.1" } } @@ -154,42 +154,42 @@ maven jetty dependency { groupId = "org.eclipse.jetty.ee10" artifactId = "jetty-ee10-servlet" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-http" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-io" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-security" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-server" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-session" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util-ajax" - version = "12.0.16" + version = "12.0.22" } dependency { groupId = "jakarta.servlet" @@ -207,12 +207,12 @@ maven jna dependency { groupId = "net.java.dev.jna" artifactId = "jna" - version = "5.15.0" + version = "5.17.0" } dependency { groupId = "net.java.dev.jna" artifactId = "jna-platform" - version = "5.15.0" + version = "5.17.0" } } @@ -225,7 +225,7 @@ maven mockito dependency { groupId = "org.mockito" artifactId = "mockito-core" - version = "5.14.2" + version = "5.18.0" } } @@ -238,12 +238,12 @@ maven sshd dependency { groupId = "org.apache.sshd" artifactId = "sshd-osgi" - version = "2.14.0" + version = "2.15.0" } dependency { groupId = "org.apache.sshd" artifactId = "sshd-sftp" - version = "2.14.0" + version = "2.15.0" } } 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 22e2b01207..0000000000 --- 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 08a0846de7..0000000000 --- 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 605a43bb13..0000000000 --- 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 83b5bb3fd2..0000000000 --- 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 99f352011b..0000000000 --- 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 cd1d1c08fa..0000000000 --- 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 0c7c846738..0000000000 --- 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 fafc689268..0000000000 --- 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 3c74497c21..0000000000 --- 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 8db1018ffb..0000000000 --- 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 378b84873f..0000000000 --- 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 8578b2cdf5..0000000000 --- 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 46055d3728..0000000000 --- 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 70a17a1ddc..0000000000 --- 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.32.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd index 480e96e2e8..59fcd8745a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd @@ -6,8 +6,6 @@ location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024 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] diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd index 8dca4cb681..2cfa0a8e7c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd @@ -6,8 +6,6 @@ location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024 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] diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd index 15931db8c7..d3e15bba6d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd @@ -6,8 +6,6 @@ location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024 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.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] 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.35.tpd index 9d00cb4c4f..ec6996e427 100644 --- 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.35.tpd @@ -1,15 +1,13 @@ -target "orbit-4.31" 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 @@ location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023 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.36.tpd index 0554a8578c..4f4658328e 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.36.tpd @@ -1,15 +1,13 @@ -target "orbit-4.30" with source configurePhase +target "orbit-4.36" 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-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.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 @@ location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2023 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 5bc67b458e..69b57de3d9 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> <packaging>pom</packaging> <name>JGit Tycho Parent</name> @@ -30,7 +30,7 @@ <properties> <java.version>17</java.version> - <tycho-version>4.0.10</tycho-version> + <tycho-version>4.0.13</tycho-version> <target-platform>jgit-4.32</target-platform> <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp> </properties> @@ -233,7 +233,7 @@ <plugin> <groupId>io.github.git-commit-id</groupId> <artifactId>git-commit-id-maven-plugin</artifactId> - <version>9.0.1</version> + <version>9.0.2</version> <executions> <execution> <id>get-the-git-infos</id> @@ -390,17 +390,17 @@ </plugin> <plugin> <artifactId>maven-clean-plugin</artifactId> - <version>3.4.0</version> + <version>3.4.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> - <version>3.1.3</version> + <version>3.1.4</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> - <version>3.1.3</version> + <version>3.1.4</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -410,7 +410,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-artifact-plugin</artifactId> - <version>3.5.3</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 60a60bb51d..c15c705c22 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-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm.test Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.diff;version="[7.2.0,7.3.0)", - org.eclipse.jgit.dircache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.merge;version="[7.2.0,7.3.0)", - org.eclipse.jgit.pgm;version="[7.2.0,7.3.0)", - org.eclipse.jgit.pgm.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.pgm.opt;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.io;version="[7.2.0,7.3.0)", +Import-Package: org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.diff;version="[7.4.0,7.5.0)", + org.eclipse.jgit.dircache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.merge;version="[7.4.0,7.5.0)", + org.eclipse.jgit.pgm;version="[7.4.0,7.5.0)", + org.eclipse.jgit.pgm.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.pgm.opt;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.io;version="[7.4.0,7.5.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 9195a369e7..d242156ccb 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.2.0-SNAPSHOT</version> + <version>7.4.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 6d6374f172..a48fcbcd5a 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 @@ package org.eclipse.jgit.pgm; 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 class AddTest extends CLIRepositoryTestCase { @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 class AddTest extends CLIRepositoryTestCase { } @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 class AddTest extends CLIRepositoryTestCase { 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/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java index 999bf434ce..d533829d52 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java @@ -96,6 +96,20 @@ public class CheckoutTest extends CLIRepositoryTestCase { } @Test + public void testCheckoutWithNoRef() throws Exception { + assertStringArrayEquals( + "a valid ref is expected", + executeExpectingException("git checkout")); + } + + @Test + public void testCheckoutWithInvalidRef() throws Exception { + assertStringArrayEquals( + ".feature is not a valid ref name", + executeExpectingException("git checkout .feature")); + } + + @Test public void testCheckoutNewBranchThatAlreadyExists() throws Exception { try (Git git = new Git(db)) { git.commit().setMessage("initial 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 c78544309b..595767d3a0 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 class DescribeTest extends CLIRepositoryTestCase { } @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 class DescribeTest extends CLIRepositoryTestCase { } @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/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF index fbcab95354..21198afc65 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -14,49 +14,50 @@ Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", 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.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.archive;version="[7.2.0,7.3.0)", - org.eclipse.jgit.awtui;version="[7.2.0,7.3.0)", - org.eclipse.jgit.blame;version="[7.2.0,7.3.0)", - org.eclipse.jgit.diff;version="[7.2.0,7.3.0)", - org.eclipse.jgit.dircache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.gitrepo;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.io;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.server;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.server.fs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs.server.s3;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.merge;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.notes;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revplot;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.pack;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http.apache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.resolver;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.ssh.jsch;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.sshd;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.io;version="[7.2.0,7.3.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.archive;version="[7.4.0,7.5.0)", + org.eclipse.jgit.awtui;version="[7.4.0,7.5.0)", + org.eclipse.jgit.blame;version="[7.4.0,7.5.0)", + org.eclipse.jgit.diff;version="[7.4.0,7.5.0)", + org.eclipse.jgit.dircache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.gitrepo;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.io;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.midx;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.server;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.server.fs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs.server.s3;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.merge;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.notes;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revplot;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.pack;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http.apache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.resolver;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.ssh.jsch;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.sshd;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.io;version="[7.4.0,7.5.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.2.0"; +Export-Package: org.eclipse.jgit.console;version="7.4.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util", - org.eclipse.jgit.pgm;version="7.2.0"; + org.eclipse.jgit.pgm;version="7.4.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util.io, org.eclipse.jgit.awtui, @@ -68,14 +69,14 @@ Export-Package: org.eclipse.jgit.console;version="7.2.0"; org.eclipse.jgit.treewalk, org.eclipse.jgit.api, javax.swing", - org.eclipse.jgit.pgm.debug;version="7.2.0"; + org.eclipse.jgit.pgm.debug;version="7.4.0"; uses:="org.eclipse.jgit.util.io, org.eclipse.jgit.pgm, org.eclipse.jetty.servlet", - org.eclipse.jgit.pgm.internal;version="7.2.0"; + org.eclipse.jgit.pgm.internal;version="7.4.0"; x-friends:="org.eclipse.jgit.pgm.test, org.eclipse.jgit.test", - org.eclipse.jgit.pgm.opt;version="7.2.0"; + org.eclipse.jgit.pgm.opt;version="7.4.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 0101464c82..cb3c28e8cf 100644 --- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.pgm - Sources Bundle-SymbolicName: org.eclipse.jgit.pgm.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="7.4.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 41b0091b77..6bf88d9aa8 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,7 @@ org.eclipse.jgit.pgm.LsTree 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 diff --git a/org.eclipse.jgit.pgm/jgit.sh b/org.eclipse.jgit.pgm/jgit.sh index a369220037..3f241e8a7a 100644 --- a/org.eclipse.jgit.pgm/jgit.sh +++ b/org.eclipse.jgit.pgm/jgit.sh @@ -110,9 +110,9 @@ then LESS=${LESS:-FSRX} export LESS - "$java" $java_args org.springframework.boot.loader.JarLauncher "$@" | $use_pager + "$java" $java_args org.springframework.boot.loader.launch.JarLauncher "$@" | $use_pager exit else - exec "$java" $java_args org.springframework.boot.loader.JarLauncher "$@" + exec "$java" $java_args org.springframework.boot.loader.launch.JarLauncher "$@" exit 1 fi diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index 81efa44cc6..14588dd6df 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.2.0-SNAPSHOT</version> + <version>7.4.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 d24b639a31..e9630e9499 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 @@ ARGS=ARGS # 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,7 +256,9 @@ unsupportedOperation=Unsupported operation: {0} untrackedFiles=Untracked files: updating=Updating {0}..{1} usage_Abbrev=Instead of using the default number of hexadecimal digits (which will vary according to the number of objects in the repository with a default of 7) of the abbreviated object name, use <n> digits, or as many digits as needed to form a unique object name. An <n> of 0 will suppress long format, only showing the closest tag. -usage_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 @@ -279,6 +282,7 @@ usage_CreateAnEmptyGitRepository=Create an empty git repository 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. @@ -300,6 +304,7 @@ usage_MakeCacheTree=Show the current cache tree structure usage_Match=Only consider tags matching the given glob(7) pattern or patterns, excluding the "refs/tags/" prefix. usage_MergeBase=Find as good common ancestors as possible for a merge usage_MergesTwoDevelopmentHistories=Merges two development histories +usage_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 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 2ebab5e5d2..dc9d77df35 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 java.util.List; 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 d2285ae64a..285fe2a96a 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 static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; 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 @@ class Blame extends TextBuiltin { private final Map<RevCommit, String> abbreviatedCommits = new HashMap<>(); - private SimpleDateFormat dateFmt; + private DateTimeFormatter dateFmt; private int begin; @@ -125,9 +125,9 @@ class Blame extends TextBuiltin { } 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 @@ class Blame extends TextBuiltin { 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/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java index 229d54d44f..7a218ec926 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java @@ -18,6 +18,7 @@ import java.util.List; import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.CheckoutConflictException; +import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.lib.Constants; @@ -94,7 +95,16 @@ class Checkout extends TextBuiltin { outw.println(MessageFormat.format( CLIText.get().switchedToBranch, Repository.shortenRefName(ref.getName()))); - } catch (RefNotFoundException e) { + } catch (InvalidRefNameException e){ + if (name == null){ + throw die(MessageFormat + .format("a valid ref is expected",e)); + } else { + throw die(MessageFormat + .format(CLIText.get().notAValidRefName, name, e)); + } + } + catch (RefNotFoundException e) { throw die(MessageFormat .format(CLIText.get().pathspecDidNotMatch, name), e); } catch (RefAlreadyExistsException e) { 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 913d7c790d..2633336e12 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 @@ class Describe extends TextBuiltin { 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/MultiPackIndex.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java new file mode 100644 index 0000000000..1844223cc9 --- /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/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java index 1576792234..a3a6782a71 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 @@ package org.eclipse.jgit.pgm; 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; @@ -51,9 +50,9 @@ import org.kohsuke.args4j.Option; @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; @@ -157,7 +156,8 @@ class Show extends TextBuiltin { // 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 @@ -232,15 +232,17 @@ class Show extends TextBuiltin { 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(); @@ -293,10 +295,12 @@ class Show extends TextBuiltin { 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$ diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java index f156b8cf4c..b7a7ec2feb 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java @@ -107,13 +107,12 @@ class BenchmarkReftable extends TextBuiltin { @SuppressWarnings({ "nls", "boxing" }) private void writeStack() throws Exception { File dir = new File(reftablePath); - File stackFile = new File(reftablePath + ".stack"); dir.mkdirs(); long start = System.currentTimeMillis(); - try (FileReftableStack stack = new FileReftableStack(stackFile, dir, - null, () -> new Config())) { + try (FileReftableStack stack = new FileReftableStack(dir, null, + () -> new Config())) { List<Ref> refs = readLsRemote().asList(); for (Ref r : refs) { 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 2f96ef7d57..22d9e3440a 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.FileInputStream; 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 @@ class RebuildCommitGraph extends TextBuiltin { 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/WriteReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java index faa2bceb74..7aff2dd9cd 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.FileOutputStream; 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 @@ class WriteReftable extends TextBuiltin { } 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 b5bf6d2bc3..bb1e950542 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 class CLIText extends TranslationBundle { } // @formatter:off + /***/ public String addIncompatibleOptions; /***/ public String alreadyOnBranch; /***/ public String alreadyUpToDate; /***/ public String answerNo; 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 6eeb24d6b4..2f516673bb 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 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent;singleton:=true -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Localization: OSGI-INF/l10n/agent Bundle-Vendor: %Bundle-Vendor -Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[7.2.0,7.3.0)" +Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[7.4.0,7.5.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.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)" +Import-Package: org.eclipse.jgit.transport.sshd;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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.2.0";x-internal:=true +Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="7.4.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 30437f25ee..0bbb111325 100644 --- a/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.agent/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ssh.apache.agent - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.apache.agent/pom.xml b/org.eclipse.jgit.ssh.apache.agent/pom.xml index feec706a25..c9a5ba0b61 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache.agent</artifactId> diff --git a/org.eclipse.jgit.ssh.apache.test/BUILD b/org.eclipse.jgit.ssh.apache.test/BUILD index dfc059f0a3..bf796c058e 100644 --- a/org.eclipse.jgit.ssh.apache.test/BUILD +++ b/org.eclipse.jgit.ssh.apache.test/BUILD @@ -8,7 +8,9 @@ load( ) DEPS = [ - "//lib:eddsa", + "//lib:bcpkix", + "//lib:bcprov", + "//lib:bcutil", "//lib:junit", "//lib:slf4j-api", "//lib:sshd-osgi", 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 f266ce106a..aa88c6aa23 100644 --- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF @@ -3,42 +3,47 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.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.14.0,2.15.0)", - org.apache.sshd.common;version="[2.14.0,2.15.0)", - org.apache.sshd.common.auth;version="[2.14.0,2.15.0)", - org.apache.sshd.common.config.keys;version="[2.14.0,2.15.0)", - org.apache.sshd.common.helpers;version="[2.14.0,2.15.0)", - org.apache.sshd.common.kex;version="[2.14.0,2.15.0)", - org.apache.sshd.common.keyprovider;version="[2.14.0,2.15.0)", - org.apache.sshd.common.session;version="[2.14.0,2.15.0)", - org.apache.sshd.common.signature;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.buffer;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.net;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.security;version="[2.14.0,2.15.0)", - org.apache.sshd.core;version="[2.14.0,2.15.0)", - org.apache.sshd.server;version="[2.14.0,2.15.0)", - org.apache.sshd.server.forward;version="[2.14.0,2.15.0)", - org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.signing.ssh;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.sshd.proxy;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit.ssh;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.sshd;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.sshd.agent;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.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.4.0,7.5.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.signing.ssh;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.sshd;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.sshd.proxy;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit.ssh;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.sshd;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.sshd.agent;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;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,2.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 2df07f7ea1..7768e95694 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId> diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AllowedSignersParseTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/signing/ssh/AllowedSignersParseTest.java index 90fde3fb28..84d8179a3d 100644 --- 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 @@ -168,6 +168,14 @@ public class AllowedSignersParseTest { "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 @@ -183,6 +191,8 @@ public class AllowedSignersParseTest { 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")); 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 0000000000..d36c38f335 --- /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 0000000000..6b61821a0f --- /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/BUILD b/org.eclipse.jgit.ssh.apache/BUILD index fd88a8a88a..c32635f7c5 100644 --- a/org.eclipse.jgit.ssh.apache/BUILD +++ b/org.eclipse.jgit.ssh.apache/BUILD @@ -12,7 +12,10 @@ java_library( resource_strip_prefix = "org.eclipse.jgit.ssh.apache/resources", resources = RESOURCES, deps = [ - "//lib:eddsa", + "//lib:bcpg", + "//lib:bcpkix", + "//lib:bcprov", + "//lib:bcutil", "//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 b6b528cec4..92d124d7a5 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF @@ -6,10 +6,10 @@ Bundle-SymbolicName: org.eclipse.jgit.ssh.apache Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-ActivationPolicy: lazy -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.2.0";x-friends:="org.eclipse.jgit.ssh.apache.test", - org.eclipse.jgit.internal.transport.sshd;version="7.2.0";x-internal:=true; +Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.4.0";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.internal.transport.sshd;version="7.4.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, @@ -24,81 +24,80 @@ Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.2.0";x-friends: org.apache.sshd.common.signature, org.apache.sshd.common.util.buffer, org.eclipse.jgit.transport", - org.eclipse.jgit.internal.transport.sshd.agent;version="7.2.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.auth;version="7.2.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.pkcs11;version="7.2.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.proxy;version="7.2.0";x-friends:="org.eclipse.jgit.ssh.apache.test", - org.eclipse.jgit.signing.ssh;version="7.2.0";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.transport.sshd;version="7.2.0"; + org.eclipse.jgit.internal.transport.sshd.agent;version="7.4.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.auth;version="7.4.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.pkcs11;version="7.4.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.proxy;version="7.4.0";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.signing.ssh;version="7.4.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.transport.sshd;version="7.4.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.2.0", - sun.security.x509 -Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)", - org.apache.sshd.agent;version="[2.14.0,2.15.0)", - org.apache.sshd.client;version="[2.14.0,2.15.0)", - org.apache.sshd.client.auth;version="[2.14.0,2.15.0)", - org.apache.sshd.client.auth.keyboard;version="[2.14.0,2.15.0)", - org.apache.sshd.client.auth.password;version="[2.14.0,2.15.0)", - org.apache.sshd.client.auth.pubkey;version="[2.14.0,2.15.0)", - org.apache.sshd.client.channel;version="[2.14.0,2.15.0)", - org.apache.sshd.client.config.hosts;version="[2.14.0,2.15.0)", - org.apache.sshd.client.config.keys;version="[2.14.0,2.15.0)", - org.apache.sshd.client.future;version="[2.14.0,2.15.0)", - org.apache.sshd.client.keyverifier;version="[2.14.0,2.15.0)", - org.apache.sshd.client.session;version="[2.14.0,2.15.0)", - org.apache.sshd.client.session.forward;version="[2.14.0,2.15.0)", - org.apache.sshd.common;version="[2.14.0,2.15.0)", - org.apache.sshd.common.auth;version="[2.14.0,2.15.0)", - org.apache.sshd.common.channel;version="[2.14.0,2.15.0)", - org.apache.sshd.common.cipher;version="[2.14.0,2.15.0)", - org.apache.sshd.common.compression;version="[2.14.0,2.15.0)", - org.apache.sshd.common.config.keys;version="[2.14.0,2.15.0)", - org.apache.sshd.common.config.keys.loader;version="[2.14.0,2.15.0)", - org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.14.0,2.15.0)", - org.apache.sshd.common.config.keys.u2f;version="[2.14.0,2.15.0)", - org.apache.sshd.common.digest;version="[2.14.0,2.15.0)", - org.apache.sshd.common.forward;version="[2.14.0,2.15.0)", - org.apache.sshd.common.future;version="[2.14.0,2.15.0)", - org.apache.sshd.common.helpers;version="[2.14.0,2.15.0)", - org.apache.sshd.common.io;version="[2.14.0,2.15.0)", - org.apache.sshd.common.kex;version="[2.14.0,2.15.0)", - org.apache.sshd.common.kex.extension;version="[2.14.0,2.15.0)", - org.apache.sshd.common.kex.extension.parser;version="[2.14.0,2.15.0)", - org.apache.sshd.common.keyprovider;version="[2.14.0,2.15.0)", - org.apache.sshd.common.mac;version="[2.14.0,2.15.0)", - org.apache.sshd.common.random;version="[2.14.0,2.15.0)", - org.apache.sshd.common.session;version="[2.14.0,2.15.0)", - org.apache.sshd.common.session.helpers;version="[2.14.0,2.15.0)", - org.apache.sshd.common.signature;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.buffer;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.buffer.keys;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.closeable;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.io;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.io.der;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.io.functors;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.io.resource;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.logging;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.net;version="[2.14.0,2.15.0)", - org.apache.sshd.common.util.security;version="[2.14.0,2.15.0)", - org.apache.sshd.core;version="[2.14.0,2.15.0)", - org.apache.sshd.server.auth;version="[2.14.0,2.15.0)", - org.apache.sshd.sftp;version="[2.14.0,2.15.0)", - org.apache.sshd.sftp.client;version="[2.14.0,2.15.0)", - org.apache.sshd.sftp.common;version="[2.14.0,2.15.0)", - org.eclipse.jgit.annotations;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.fnmatch;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.transport.sshd.agent;version="7.4.0" +Import-Package: org.bouncycastle.jce.provider;version="[1.80.0,2.0.0)", + 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.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.fnmatch;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 c19e0aa253..02b4324cd3 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ssh.apache - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml index a002290378..2d6cd39ae4 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.2.0-SNAPSHOT</version> + <version>7.4.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/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties index 6048239391..773c4b9432 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 expected {1} key for host ''{2}'' has the fingerprints:\n\ 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? 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 index cfbe7a78a7..80b171f216 100644 --- 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 @@ -21,6 +21,7 @@ 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; @@ -36,8 +37,6 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.TimeZone; -import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -64,8 +63,6 @@ final class AllowedSigners extends ModifiableFileWatcher { private static final String VALID_BEFORE = "valid-before="; //$NON-NLS-1$ - private static final String SSH_KEY_PREFIX = "ssh-"; //$NON-NLS-1$ - private static final DateTimeFormatter SSH_DATE_FORMAT = new DateTimeFormatterBuilder() .appendValue(ChronoField.YEAR, 4) .appendValue(ChronoField.MONTH_OF_YEAR, 2) @@ -323,8 +320,7 @@ final class AllowedSigners extends ModifiableFileWatcher { && Character.isWhitespace(line.charAt(CERT_AUTHORITY.length()))) || matches(line, NAMESPACES, 0) || matches(line, VALID_AFTER, 0) - || matches(line, VALID_BEFORE, 0) - || matches(line, SSH_KEY_PREFIX, 0)) { + || matches(line, VALID_BEFORE, 0)) { throw new StreamCorruptedException( SshdText.get().signAllowedSignersNoIdentities); } @@ -449,7 +445,9 @@ final class AllowedSigners extends ModifiableFileWatcher { s.substring(start))); } String keyType = s.substring(start, endOfKeyType); - if (!keyType.startsWith(SSH_KEY_PREFIX)) { + 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))); @@ -482,12 +480,8 @@ final class AllowedSigners extends ModifiableFileWatcher { if (isUTC) { return time.atOffset(ZoneOffset.UTC).toInstant(); } - TimeZone tz = SystemReader.getInstance().getTimeZone(); - // Since there are a few TimeZone IDs that are not recognized by ZoneId, - // use offsets. - return time.atOffset(ZoneOffset.ofTotalSeconds( - (int) TimeUnit.MILLISECONDS.toSeconds(tz.getRawOffset()))) - .toInstant(); + ZoneId tz = SystemReader.getInstance().getTimeZoneId(); + return time.atZone(tz).toInstant(); } // OpenSSH uses the backslash *only* to quote the double-quote. 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 96829b7365..6b2345df1b 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.HostPatternsHolder; 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 @@ public class KnownHostEntryReader { 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 @@ public class KnownHostEntryReader { 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 2b4f7e50ff..acb77c5bb7 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.ArrayList; 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.config.hosts.KnownHostHashValue; 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 class OpenSshServerKeyDatabase 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 class OpenSshServerKeyDatabase 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 class OpenSshServerKeyDatabase 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 class OpenSshServerKeyDatabase 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 @@ public class OpenSshServerKeyDatabase 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 + } + } + if (haveCert == isCert && !haveCert && !revoked) { + // Server sent a different key. + if (modifiedKeyType == null) { modified[0] = current; - // Keep going -- maybe there's another entry for this - // host + 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; + } } - break; + // 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 @@ public class OpenSshServerKeyDatabase 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 class OpenSshServerKeyDatabase 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 @@ public class OpenSshServerKeyDatabase } try { PublicKey serverKey = keyPart.resolvePublicKey(null, - PublicKeyEntryResolver.IGNORING); + PublicKeyEntryResolver.UNSUPPORTED); if (serverKey == null) { LOG.warn(format( SshdText.get().knownHostsUnknownKeyType, @@ -625,7 +710,7 @@ public class OpenSshServerKeyDatabase 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 @@ public class OpenSshServerKeyDatabase 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 @@ public class OpenSshServerKeyDatabase 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 @@ public class OpenSshServerKeyDatabase } } 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/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java index 0533b651e0..e40137870b 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 @@ -83,6 +83,7 @@ public final class SshdText extends TranslationBundle { /***/ public String knownHostsModifiedKeyDenyMsg; /***/ public String knownHostsModifiedKeyStorePrompt; /***/ public String knownHostsModifiedKeyWarning; + /***/ public String knownHostsRevokedCertificateMsg; /***/ public String knownHostsRevokedKeyMsg; /***/ public String knownHostsUnknownKeyMsg; /***/ public String knownHostsUnknownKeyPrompt; 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 a84ee37ffb..0000000000 --- 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 4a8b92518e..d4e6875ed8 100644 --- a/org.eclipse.jgit.ssh.jsch.test/BUILD +++ b/org.eclipse.jgit.ssh.jsch.test/BUILD @@ -8,7 +8,9 @@ junit_tests( 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 9cf812ce3b..5c3d39678b 100644 --- a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF @@ -3,20 +3,20 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.jsch.test Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.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.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit.ssh;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.ssh.jsch;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit.ssh;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.ssh.jsch;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.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 e84ac4d574..f09249bd8c 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.jsch.test</artifactId> diff --git a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF index ed6115b046..6bcec890ee 100644 --- a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF @@ -3,19 +3,19 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.jsch Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch;singleton:=true -Fragment-Host: org.eclipse.jgit;bundle-version="[7.2.0,7.3.0)" +Fragment-Host: org.eclipse.jgit;bundle-version="[7.4.0,7.5.0)" Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/jsch Bundle-ActivationPolicy: lazy -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="7.2.0" +Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="7.4.0" Import-Package: com.jcraft.jsch;version="[0.1.37,0.2.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.io;version="[7.2.0,7.3.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.io;version="[7.4.0,7.5.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 4e8da25752..cf10f718ee 100644 --- a/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ssh.jsch - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.jsch.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.jsch/pom.xml b/org.eclipse.jgit.ssh.jsch/pom.xml index fdc5ffb8b3..4871c4e0c9 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.jsch</artifactId> diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD index 29f5b36149..7755df0499 100644 --- a/org.eclipse.jgit.test/BUILD +++ b/org.eclipse.jgit.test/BUILD @@ -53,6 +53,11 @@ tests(tests = glob( 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 c1aaea93b6..8582bcf818 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.test Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -20,65 +20,68 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", 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.2.0,7.3.0)", - org.eclipse.jgit.api;version="[7.2.0,7.3.0)", - org.eclipse.jgit.api.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.archive;version="[7.2.0,7.3.0)", - org.eclipse.jgit.attributes;version="[7.2.0,7.3.0)", - org.eclipse.jgit.awtui;version="[7.2.0,7.3.0)", - org.eclipse.jgit.blame;version="[7.2.0,7.3.0)", - org.eclipse.jgit.diff;version="[7.2.0,7.3.0)", - org.eclipse.jgit.dircache;version="[7.2.0,7.3.0)", - org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.events;version="[7.2.0,7.3.0)", - org.eclipse.jgit.fnmatch;version="[7.2.0,7.3.0)", - org.eclipse.jgit.gitrepo;version="[7.2.0,7.3.0)", - org.eclipse.jgit.hooks;version="[7.2.0,7.3.0)", - org.eclipse.jgit.ignore;version="[7.2.0,7.3.0)", - org.eclipse.jgit.ignore.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.diff;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.fsck;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.commitgraph;version="7.2.0", - org.eclipse.jgit.internal.storage.dfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.io;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.memory;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.connectivity;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.parser;version="[7.2.0,7.3.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit;version="[7.2.0,7.3.0)", - org.eclipse.jgit.junit.time;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lfs;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.logging;version="[7.2.0,7.3.0)", - org.eclipse.jgit.merge;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.notes;version="[7.2.0,7.3.0)", - org.eclipse.jgit.patch;version="[7.2.0,7.3.0)", - org.eclipse.jgit.pgm;version="[7.2.0,7.3.0)", - org.eclipse.jgit.pgm.internal;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revplot;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.file;version="[7.2.0,7.3.0)", - org.eclipse.jgit.storage.pack;version="[7.2.0,7.3.0)", - org.eclipse.jgit.submodule;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.http;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport.resolver;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.treewalk.filter;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.io;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util.sha1;version="[7.2.0,7.3.0)", + org.eclipse.jgit.annotations;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api;version="[7.4.0,7.5.0)", + org.eclipse.jgit.api.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.archive;version="[7.4.0,7.5.0)", + org.eclipse.jgit.attributes;version="[7.4.0,7.5.0)", + org.eclipse.jgit.awtui;version="[7.4.0,7.5.0)", + org.eclipse.jgit.blame;version="[7.4.0,7.5.0)", + org.eclipse.jgit.blame.cache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.diff;version="[7.4.0,7.5.0)", + org.eclipse.jgit.dircache;version="[7.4.0,7.5.0)", + org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.events;version="[7.4.0,7.5.0)", + org.eclipse.jgit.fnmatch;version="[7.4.0,7.5.0)", + org.eclipse.jgit.gitrepo;version="[7.4.0,7.5.0)", + org.eclipse.jgit.hooks;version="[7.4.0,7.5.0)", + org.eclipse.jgit.ignore;version="[7.4.0,7.5.0)", + org.eclipse.jgit.ignore.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.diff;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.fsck;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.commitgraph;version="7.4.0", + org.eclipse.jgit.internal.storage.dfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.io;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.memory;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.midx;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.connectivity;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.parser;version="[7.4.0,7.5.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit;version="[7.4.0,7.5.0)", + org.eclipse.jgit.junit.time;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lfs;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.logging;version="[7.4.0,7.5.0)", + org.eclipse.jgit.merge;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.notes;version="[7.4.0,7.5.0)", + org.eclipse.jgit.patch;version="[7.4.0,7.5.0)", + org.eclipse.jgit.pgm;version="[7.4.0,7.5.0)", + org.eclipse.jgit.pgm.internal;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revplot;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.file;version="[7.4.0,7.5.0)", + org.eclipse.jgit.storage.pack;version="[7.4.0,7.5.0)", + org.eclipse.jgit.submodule;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.http;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport.resolver;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.treewalk.filter;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.io;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util.sha1;version="[7.4.0,7.5.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/ignore/CGitVsJGitRandomIgnorePatternTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java index 23a267c8dc..47a410bdee 100644 --- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java +++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java @@ -164,7 +164,7 @@ public class CGitVsJGitRandomIgnorePatternTest { private String readProcessStream(InputStream processStream) throws IOException { try (BufferedReader stdOut = new BufferedReader( - new InputStreamReader(processStream))) { + new InputStreamReader(processStream, UTF_8))) { StringBuilder out = new StringBuilder(); String s; 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 0000000000..334e52b042 --- /dev/null +++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/midx/CgitMidxCompatibilityTest.java @@ -0,0 +1,219 @@ +/* + * 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.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.ByteArrayInputStream; +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)); + + } + + @Test + public void jgit_loadsCgitMidx() + throws IOException, InterruptedException { + assertEquals("cgit exit code", 0, run_cgit_multipackindex_write()); + byte[] cgitMidxBytes = readCgitMidx(); + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(cgitMidxBytes)); + assertEquals(7, midx.getPackNames().length); + } + + 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 c936b09fd7..39d317a136 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.2.0-SNAPSHOT</version> + <version>7.4.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 170bf0c460..41f76d090a 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 @@ def tests(tests): 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/test/resources/multi-pack-index.v1 b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/multi-pack-index.v1 Binary files differnew file mode 100644 index 0000000000..223febeb26 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/multi-pack-index.v1 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 1c2e995bbb..226677229c 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 class AddCommandTest extends RepositoryTestCase { 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 class AddCommandTest extends RepositoryTestCase { 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 class AddCommandTest extends RepositoryTestCase { // 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 class AddCommandTest extends RepositoryTestCase { "[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/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java index be3b33a9c5..3f5c5da55a 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.ConfigConstants; 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 @@ public class CherryPickCommandTest extends RepositoryTestCase { 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 db5b27c2ab..661878fa07 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 @@ public class CloneCommandTest extends RepositoryTestCase { 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); } @@ -796,7 +797,7 @@ public class CloneCommandTest extends RepositoryTestCase { 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(); @@ -812,7 +813,6 @@ public class CloneCommandTest extends RepositoryTestCase { addRepoToClose(git2.getRepository()); assertEquals(BranchRebaseMode.REBASE, git2.getRepository().getConfig().getEnum( - BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, "test", ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE)); @@ -829,7 +829,6 @@ public class CloneCommandTest extends RepositoryTestCase { 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 57e5d4958f..4e5f44e5a6 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.junit.RepositoryTestCase; 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 class CommitAndLogCommandTest extends RepositoryTestCase { 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 class CommitAndLogCommandTest extends RepositoryTestCase { 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 e74e234297..21cfcc4e34 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,9 +19,9 @@ import static org.junit.Assert.fail; 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; @@ -435,10 +435,12 @@ public class CommitCommandTest extends RepositoryTestCase { 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()); } } @@ -455,12 +457,15 @@ public class CommitCommandTest extends RepositoryTestCase { 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())); } } @@ -486,11 +491,11 @@ public class CommitCommandTest extends RepositoryTestCase { 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) @@ -499,7 +504,8 @@ public class CommitCommandTest extends RepositoryTestCase { PersonIdent amendedAuthor = amended.getAuthorIdent(); assertEquals(authorName, amendedAuthor.getName()); assertEquals(authorEmail, amendedAuthor.getEmailAddress()); - assertEquals(authorDate.getTime(), amendedAuthor.getWhen().getTime()); + assertEquals(authorDate.getEpochSecond(), + amendedAuthor.getWhenAsInstant().getEpochSecond()); } } 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 ab87fa9662..060e6d3e84 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 @@ package org.eclipse.jgit.api; import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -87,6 +88,9 @@ public class DescribeCommandTest extends RepositoryTestCase { 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 class DescribeCommandTest extends RepositoryTestCase { 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 @@ public class DescribeCommandTest extends RepositoryTestCase { .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/FetchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java index 3ec454cfc3..3731347f11 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 class FetchCommandTest extends RepositoryTestCase { 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 f98db3497b..6090d5efbe 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 @@ package org.eclipse.jgit.api; 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 class GarbageCollectCommandTest extends RepositoryTestCase { @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 class GarbageCollectCommandTest extends RepositoryTestCase { 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 76934343da..e847e72415 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 static org.junit.Assert.fail; 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 class GitConstructionTest extends RepositoryTestCase { 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/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java index 917b6c3297..1ec506798c 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.Assert.fail; 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; 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.FS; 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 class MergeCommandTest extends RepositoryTestCase { 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 class MergeCommandTest extends RepositoryTestCase { 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 class MergeCommandTest extends RepositoryTestCase { 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 class MergeCommandTest extends RepositoryTestCase { 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 class MergeCommandTest extends RepositoryTestCase { 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 class MergeCommandTest extends RepositoryTestCase { .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 class MergeCommandTest extends RepositoryTestCase { .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 class MergeCommandTest extends RepositoryTestCase { } } + @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 6d5e45c98f..695681de8d 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 @@ -480,7 +480,7 @@ public class PullCommandTest extends RepositoryTestCase { @Test /** without config it should merge */ public void testPullWithoutConfig() throws Exception { - Callable<PullResult> setup = target.pull()::call; + Callable<PullResult> setup = target.pull(); doTestPullWithRebase(setup, TestPullMode.MERGE); } 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 70e990dedf..d1696d62a8 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.IOException; 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 class PushCommandTest extends RepositoryTestCase { 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 02e3a2e06f..4c8cf06a67 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.File; 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.ObjectLoader; 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 class RebaseCommandTest extends RepositoryTestCase { 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 534ebd9c61..add5886c2d 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 class RenameBranchCommandTest extends RepositoryTestCase { 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 class RenameBranchCommandTest extends RepositoryTestCase { 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 class RenameBranchCommandTest extends RepositoryTestCase { 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 8a479a0ca0..99873e1be1 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.Constants; 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 class ResetCommandTest extends RepositoryTestCase { 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 afd6708d21..89fdb32220 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 @@ -29,6 +29,7 @@ import org.eclipse.jgit.junit.RepositoryTestCase; 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; @@ -87,10 +88,11 @@ public class RevertCommandTest extends RepositoryTestCase { 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 \"")); } @@ -170,10 +172,11 @@ public class RevertCommandTest extends RepositoryTestCase { 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 \"")); } @@ -223,10 +226,11 @@ public class RevertCommandTest extends RepositoryTestCase { 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 \"")); } @@ -431,12 +435,13 @@ public class RevertCommandTest extends RepositoryTestCase { 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/StashCreateCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java index 5d0ab05174..18cd21a5d7 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 class StashCreateCommandTest extends RepositoryTestCase { 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 c81731d746..d937579283 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 class StashDropCommandTest extends RepositoryTestCase { 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 class StashDropCommandTest extends RepositoryTestCase { 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 class StashDropCommandTest extends RepositoryTestCase { 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 class StashDropCommandTest extends RepositoryTestCase { 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 class StashDropCommandTest extends RepositoryTestCase { 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 f47f447375..c2c06b2477 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 @@ import org.junit.Test; /** 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 class BlameGeneratorTest extends RepositoryTestCase { 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 class BlameGeneratorTest extends RepositoryTestCase { 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 class BlameGeneratorTest extends RepositoryTestCase { 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 class BlameGeneratorTest extends RepositoryTestCase { } // 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 class BlameGeneratorTest extends RepositoryTestCase { 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/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java index f23469eda0..35b953320e 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.attributes.Attribute.State; 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 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { 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 1fcfbaf0fa..dbbcb75da9 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 java.io.InputStream; 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 class AttributesNodeTest { 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 7b573e122e..c6c91386a2 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.attributes.Attribute.State; 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 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { 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/blame/BlameGeneratorCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameGeneratorCacheTest.java new file mode 100644 index 0000000000..3e4ac1f993 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/blame/BlameGeneratorCacheTest.java @@ -0,0 +1,552 @@ +/* + * 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 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); + // Cache not needed because c1 doesn't have parents + assertCacheUsage(c4, blameAndCache(c1), false, 4); + } + + @Test + public void blame_simple_createdMidHistory_correctRegions() throws Exception { + String c1Content = lines("L1C1", "L2C1", "L3C1"); + String c2Content = lines("L1C1", "L2C1", "L3C1", "L4C2"); + String c3Content = lines("L1C1", "L2C3", "L3C3", "L4C2"); + String c4Content = lines("L1C1", "L2C4", "L3C3", "L4C4"); + + RevCommit c0, c1, c2, c3, c4; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c0 = r.commit().add("otherfile", "content").create(); + c1 = r.commit().parent(c0).add(FILE, c1Content).create(); + c2 = r.commit().parent(c1).add(FILE, c2Content).create(); + c3 = r.commit().parent(c2).add(FILE, c3Content).create(); + c4 = r.commit().parent(c3).add(FILE, c4Content).create(); + } + + 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, FILE), expectedRegions, 4); + assertRegions(c4, blameAndCache(c3, FILE), expectedRegions, 4); + assertRegions(c4, blameAndCache(c2, FILE), expectedRegions, 4); + assertRegions(c4, blameAndCache(c1, FILE), expectedRegions, 4); + assertRegions(c4, blameAndCache(c0, FILE), expectedRegions, 4); + } + + @Test + public void blame_simple_createdMidHistory_cacheUsage() throws Exception { + String c1Content = lines("L1C1", "L2C1", "L3C1"); + String c2Content = lines("L1C1", "L2C1", "L3C1", "L4C2"); + String c3Content = lines("L1C1", "L2C3", "L3C3", "L4C2"); + String c4Content = lines("L1C1", "L2C4", "L3C3", "L4C4"); + + RevCommit c0, c1, c2, c3, c4; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c0 = r.commit().add("otherfile", "content").create(); + c1 = r.commit().parent(c0).add(FILE, c1Content).create(); + c2 = r.commit().parent(c1).add(FILE, c2Content).create(); + c3 = r.commit().parent(c2).add(FILE, c3Content).create(); + c4 = r.commit().parent(c3).add(FILE, c4Content).create(); + } + + assertCacheUsage(c4, null, false, 4); + assertCacheUsage(c4, emptyCache(), false, 4); + assertCacheUsage(c4, blameAndCache(c4, FILE), true, 1); + assertCacheUsage(c4, blameAndCache(c3, FILE), true, 2); + assertCacheUsage(c4, blameAndCache(c2, FILE), true, 3); + // Cache not needed because c1 created the file + assertCacheUsage(c4, blameAndCache(c1, FILE), false, 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_overwrite_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); + + // 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), false, 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), false, 3); + } + + @Test + public void blame_cacheOnlyOnChange_unmodifiedInSomeCommits_cacheUsage() throws Exception { + String README = "README"; + String fileC1Content = lines("L1C1", "L2C1", "L3C1"); + String fileC2Content = lines("L1C1", "L2C1", "L3C1", "L4C2"); + String fileC3Content = lines("L1C1", "L2C3", "L3C3", "L4C2"); + String fileC4Content = lines("L1C1", "L2C4", "L3C3", "L4C4"); + + RevCommit c1, c2, c3, c4, ni; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = r.commit().add(FILE, fileC1Content).create(); + c2 = r.commit().parent(c1).add(FILE, fileC2Content).create(); + // Keep FILE and edit 100 times README + ni = c2; + for (int i = 0; i < 100; i++) { + ni = r.commit().parent(ni).add(README, "whatever " + i).create(); + } + c3 = r.commit().parent(ni).add(FILE, fileC3Content).create(); + c4 = r.commit().parent(c3).add(FILE, fileC4Content).create(); + r.branch("refs/heads/master").update(c4); + } + + InMemoryBlameCache empty = emptyCache(); + assertCacheUsage(c4, empty, false, 104); + assertEquals(3, empty.callCount); + + InMemoryBlameCache c4Cached = blameAndCache(c4, FILE); + assertCacheUsage(c4, c4Cached, true, 1); + assertEquals(1, c4Cached.callCount); + + InMemoryBlameCache c3Cached = blameAndCache(c3, FILE); + assertCacheUsage(c4, c3Cached, true, 2); + assertEquals(2, c3Cached.callCount); + + // This commit doesn't touch the file, shouldn't check the cache + InMemoryBlameCache niCached = blameAndCache(ni, FILE); + assertCacheUsage(c4, niCached, false, 104); + assertEquals(3, niCached.callCount); + + InMemoryBlameCache c2Cached = blameAndCache(c2, FILE); + assertCacheUsage(c4, c2Cached, true, 103); + assertEquals(3, c2Cached.callCount); + + // No parents, c1 doesn't need cache. + InMemoryBlameCache c1Cached = blameAndCache(c1, FILE); + assertCacheUsage(c4, c1Cached, false, 104); + assertEquals(3, c1Cached.callCount); + } + + @Test + public void blame_cacheOnlyOnChange_renameWithoutChange_cacheUsage() throws Exception { + String OTHER = "other.txt"; + String c1Content = lines("L1C1", "L2C1", "L3C1"); + String c2Content = lines("L1C1", "L2C1", "L3C1", "L4C2"); + + RevCommit c1, c2, c3; + try (TestRepository<FileRepository> r = new TestRepository<>(db)) { + c1 = r.commit().add(OTHER, c1Content).create(); + c2 = r.commit().parent(c1).add(OTHER, c2Content).create(); + c3 = r.commit().parent(c2).rm(OTHER).add(FILE, c2Content).create(); + r.branch("refs/heads/master").update(c3); + } + + assertCacheUsage(c3, null, false, 3); + assertCacheUsage(c3, emptyCache(), false, 3); + assertCacheUsage(c3, blameAndCache(c3, FILE), true, 1); + assertCacheUsage(c3, blameAndCache(c2, OTHER), true, 2); + assertCacheUsage(c3, blameAndCache(c1, OTHER), false, 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 cacheHit, int candidatesVisited) throws IOException { + try (BlameGenerator gen = new BlameGenerator(db, FILE, cache)) { + gen.push(null, db.parseCommit(commit)); + consume(gen); + assertEquals(cacheHit, 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 { + return blameAndCache(commit, FILE); + } + + private InMemoryBlameCache blameAndCache(RevCommit commit, String path) + throws IOException { + List<CacheRegion> regions; + try (BlameGenerator generator = new BlameGenerator(db, path)) { + generator.push(null, commit); + regions = consume(generator).stream() + .map(EmittedRegion::asCacheRegion) + .toList(); + } + InMemoryBlameCache cache = new InMemoryBlameCache("<x>"); + cache.put(commit, path, 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 commit(r, Map.of(FILE, contents), parents); + } + + private static RevCommit commit(TestRepository<?> r, + Map<String, String> fileContents, RevCommit... parents) + throws Exception { + TestRepository<?>.CommitBuilder builder = r.commit(); + for (RevCommit commit : parents) { + builder.parent(commit); + } + fileContents.forEach((path, content) -> { + try { + builder.add(path, content); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return builder.create(); + } + + 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; + + private int callCount; + + public InMemoryBlameCache(String description) { + this.description = description; + } + + @Override + public List<CacheRegion> get(Repository repo, ObjectId commitId, + String path) throws IOException { + callCount++; + 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 0000000000..1b28676fbf --- /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/EditListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java index f657bab771..a2c20aaaba 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java @@ -28,7 +28,7 @@ public class EditListTest { assertTrue(l.isEmpty()); assertEquals("EditList[]", l.toString()); - assertEquals(l, l); + assertTrue(l.equals(l)); assertEquals(new EditList(), l); assertFalse(l.equals("")); assertEquals(l.hashCode(), new EditList().hashCode()); @@ -44,7 +44,7 @@ public class EditListTest { assertSame(e, l.get(0)); assertSame(e, l.iterator().next()); - assertEquals(l, l); + assertTrue(l.equals(l)); assertFalse(l.equals(new EditList())); final EditList l2 = new EditList(); @@ -69,7 +69,7 @@ public class EditListTest { assertSame(e1, i.next()); assertSame(e2, i.next()); - assertEquals(l, l); + assertTrue(l.equals(l)); assertFalse(l.equals(new EditList())); final EditList l2 = new EditList(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java index 8ab9bb12de..86c6d77cc6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java @@ -98,7 +98,7 @@ public class EditTest { final Edit e1 = new Edit(1, 2, 3, 4); final Edit e2 = new Edit(1, 2, 3, 4); - assertEquals(e1, e1); + assertTrue(e1.equals(e1)); assertEquals(e2, e1); assertEquals(e1, e2); assertEquals(e1.hashCode(), e2.hashCode()); 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 fca27d32aa..0949d040e9 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 @@ -12,12 +12,16 @@ package org.eclipse.jgit.gitrepo; 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.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.IOException; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -221,4 +225,33 @@ public class ManifestParserTest { testNormalize("", ""); testNormalize("a/b", "a/b"); } + + @Test + public void testXXE() throws Exception { + File externalEntity = File.createTempFile("injected", "xml"); + externalEntity.deleteOnExit(); + Files.write(externalEntity.toPath(), + "<evil>injected xml</evil>" + .getBytes(UTF_8), + StandardOpenOption.WRITE); + String baseUrl = "https://git.google.com/"; + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<!DOCTYPE booo [ <!ENTITY foobar SYSTEM \"") + .append(externalEntity.getPath()).append("\"> ]>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("&foobar;") + .append("<project path=\"foo\" name=\"foo\" groups=\"a,test\" />") + .append("</manifest>"); + + IOException e = assertThrows(IOException.class, + () -> new ManifestParser(null, null, "master", baseUrl, null, + null) + .read(new ByteArrayInputStream( + xmlContent.toString().getBytes(UTF_8)))); + assertTrue(e.getCause().getMessage().contains("DOCTYPE")); + } + } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java index 6112952549..6983eaa354 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/BasicRuleTest.java @@ -31,7 +31,7 @@ public class BasicRuleTest { assertFalse(rule1.getNegation()); assertTrue(rule3.getNegation()); assertNotEquals(rule1, null); - assertEquals(rule1, rule1); + assertTrue(rule1.equals(rule1)); assertEquals(rule1, rule2); assertNotEquals(rule1, rule3); assertNotEquals(rule1, rule4); 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 f9fbfe8db0..80bd689084 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 @@ -17,10 +17,9 @@ 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.Date; -import java.util.GregorianCalendar; import java.util.concurrent.TimeUnit; import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; @@ -50,7 +49,7 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.ReceiveCommand; -import org.eclipse.jgit.util.GitDateParser; +import org.eclipse.jgit.util.GitTimeParser; import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; @@ -1183,7 +1182,8 @@ public class DfsGarbageCollectorTest { DfsReader reader = odb.newReader(); DfsPackFile gcPack = findFirstBySource(odb.getPacks(), GC); assertTrue(gcPack.hasObjectSizeIndex(reader)); - assertEquals(12, gcPack.getIndexedObjectSize(reader, headsBlob)); + assertEquals(12, gcPack.getIndexedObjectSize(reader, + gcPack.findIdxPosition(reader, headsBlob))); } @Test @@ -1204,7 +1204,8 @@ public class DfsGarbageCollectorTest { DfsReader reader = odb.newReader(); DfsPackFile gcPack = findFirstBySource(odb.getPacks(), GC); assertTrue(gcPack.hasObjectSizeIndex(reader)); - assertEquals(-1, gcPack.getIndexedObjectSize(reader, tooSmallBlob)); + assertEquals(-1, gcPack.getIndexedObjectSize(reader, + gcPack.findIdxPosition(reader, tooSmallBlob))); } @Test @@ -1294,23 +1295,22 @@ public class DfsGarbageCollectorTest { DfsPackDescription t1 = odb.newPack(INSERT); Ref next = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, "refs/heads/next", commit0.copy()); - long currentDay = new Date().getTime(); - GregorianCalendar cal = new GregorianCalendar(SystemReader - .getInstance().getTimeZone(), SystemReader.getInstance() - .getLocale()); - long ten_days_ago = GitDateParser.parse("10 days ago",cal,SystemReader.getInstance() - .getLocale()).getTime() ; - long twenty_days_ago = GitDateParser.parse("20 days ago",cal,SystemReader.getInstance() - .getLocale()).getTime() ; - long thirty_days_ago = GitDateParser.parse("30 days ago",cal,SystemReader.getInstance() - .getLocale()).getTime() ;; - long fifty_days_ago = GitDateParser.parse("50 days ago",cal,SystemReader.getInstance() - .getLocale()).getTime() ; - PersonIdent who2 = new PersonIdent("J.Author", "authemail", currentDay, -8 * 60); - PersonIdent who3 = new PersonIdent("J.Author", "authemail", ten_days_ago, -8 * 60); - PersonIdent who4 = new PersonIdent("J.Author", "authemail", twenty_days_ago, -8 * 60); - PersonIdent who5 = new PersonIdent("J.Author", "authemail", thirty_days_ago, -8 * 60); - PersonIdent who6 = new PersonIdent("J.Author", "authemail", fifty_days_ago, -8 * 60); + 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); @@ -1332,7 +1332,7 @@ public class DfsGarbageCollectorTest { gc = new DfsGarbageCollector(repo); gc.setReftableConfig(new ReftableConfig()); // Expire ref log entries older than 30 days - gc.setRefLogExpire(Instant.ofEpochMilli(thirty_days_ago)); + gc.setRefLogExpire(thirty_days_ago); run(gc); // Single GC pack present with all objects. @@ -1360,9 +1360,7 @@ public class DfsGarbageCollectorTest { assertEquals(lc.getRefName(),"refs/heads/branch2"); // Old entries are purged assertFalse(lc.next()); - } - } 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 0b558edf2c..efa98de549 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 @@ -214,7 +214,7 @@ public class DfsInserterTest { } @Test - public void testNoCheckExisting() throws IOException { + public void testNoDuplicates() throws IOException { byte[] contents = Constants.encode("foo"); ObjectId fooId; try (ObjectInserter ins = db.newObjectInserter()) { @@ -224,21 +224,20 @@ public class DfsInserterTest { assertEquals(1, db.getObjectDatabase().listPacks().size()); try (ObjectInserter ins = db.newObjectInserter()) { - ((DfsInserter) ins).checkExisting(false); + ins.insert(Constants.OBJ_BLOB, Constants.encode("bar")); assertEquals(fooId, ins.insert(Constants.OBJ_BLOB, contents)); ins.flush(); } assertEquals(2, db.getObjectDatabase().listPacks().size()); - // Verify that we have a foo in both INSERT packs. + // Newer packs are first. Verify that foo is only in the second pack try (DfsReader reader = new DfsReader(db.getObjectDatabase())) { DfsPackFile packs[] = db.getObjectDatabase().getPacks(); - assertEquals(2, packs.length); DfsPackFile p1 = packs[0]; assertEquals(PackSource.INSERT, p1.getPackDescription().getPackSource()); - assertTrue(p1.hasObject(reader, fooId)); + assertFalse(p1.hasObject(reader, fooId)); DfsPackFile p2 = packs[1]; assertEquals(PackSource.INSERT, @@ -310,7 +309,8 @@ public class DfsInserterTest { assertEquals(PackSource.INSERT, insertPack.getPackDescription().getPackSource()); assertTrue(insertPack.hasObjectSizeIndex(reader)); - assertEquals(contents.length, insertPack.getIndexedObjectSize(reader, fooId)); + assertEquals(contents.length, insertPack.getIndexedObjectSize(reader, + insertPack.findIdxPosition(reader, fooId))); } private static String readString(ObjectLoader loader) throws IOException { 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 9680019f88..f2129fd3c5 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 @@ -131,7 +131,8 @@ public class DfsPackFileTest { DfsReader reader = db.getObjectDatabase().newReader(); DfsPackFile pack = db.getObjectDatabase().getPacks()[0]; assertTrue(pack.hasObjectSizeIndex(reader)); - assertEquals(800, pack.getIndexedObjectSize(reader, blobId)); + assertEquals(800, pack.getIndexedObjectSize(reader, + pack.findIdxPosition(reader, blobId))); } @Test 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 c1cd231c66..9d26978d66 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 @@ -65,6 +65,7 @@ public class DfsPackParserTest { DfsReader reader = repo.getObjectDatabase().newReader(); PackList packList = repo.getObjectDatabase().getPackList(); assertEquals(1, packList.packs.length); - assertEquals(1, packList.packs[0].getIndexedObjectSize(reader, blobA)); + assertEquals(1, packList.packs[0].getIndexedObjectSize(reader, + packList.packs[0].findIdxPosition(reader, blobA))); } } 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 1af42cb229..a0afc3ef13 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 @@ -1263,7 +1263,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } 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/FileReftableStackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java index 6c7992716c..e8363ce21d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java @@ -81,8 +81,7 @@ public class FileReftableStackTest { } public void testCompaction(int N) throws Exception { - try (FileReftableStack stack = new FileReftableStack( - new File(reftableDir, "refs"), reftableDir, null, + try (FileReftableStack stack = new FileReftableStack(reftableDir, null, () -> new Config())) { writeBranches(stack, "refs/heads/branch%d", 0, N); MergedReftable table = stack.getMergedReftable(); @@ -124,8 +123,7 @@ public class FileReftableStackTest { // Can't delete in-use files on Windows. assumeFalse(SystemReader.getInstance().isWindows()); - try (FileReftableStack stack = new FileReftableStack( - new File(reftableDir, "refs"), reftableDir, null, + try (FileReftableStack stack = new FileReftableStack(reftableDir, null, () -> new Config())) { outer: for (int i = 0; i < 10; i++) { final long next = stack.getMergedReftable().maxUpdateIndex() @@ -152,8 +150,8 @@ public class FileReftableStackTest { } } assertThrows(FileNotFoundException.class, - () -> new FileReftableStack(new File(reftableDir, "refs"), - reftableDir, null, () -> new Config())); + () -> new FileReftableStack(reftableDir, null, + () -> new Config())); } @Test 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 32342e3563..5756b41442 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.assertNull; 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.ArrayList; 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.lib.RepositoryCache; 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 class FileReftableTest extends SampleDataRepositoryTestCase { @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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { .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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { // 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { // 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 class FileReftableTest extends SampleDataRepositoryTestCase { 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 6cad8b6c62..434f7e4bef 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 static org.junit.Assert.assertTrue; 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 class GcBasicPackingTest extends GcTestCase { // 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/GcPruneNonReferencedTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPruneNonReferencedTest.java index ca0f6842fc..84ec132e24 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.assertNotNull; 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 class GcPruneNonReferencedTest extends GcTestCase { @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/GcSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java index 3cd766c4e9..af52e2cb85 100644 --- 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 @@ -20,6 +20,7 @@ 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 { @@ -51,11 +52,19 @@ public class GcSinceBitmapStatisticsTest extends GcTestCase { } @Test - public void testShouldReportNoPacksDirectlyAfterGc() throws Exception { - // given + public void testShouldReportNoPacksFilesSinceBitmapWhenPackfilesAreOlderThanBitmapFile() + throws Exception { addCommit(null); - gc.gc().get(); + 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); } @@ -79,8 +88,11 @@ public class GcSinceBitmapStatisticsTest extends GcTestCase { // progress & pack addCommit(parent); - tr.packAndPrune(); + assertEquals(1L, gc.getStatistics().numberOfPackFiles); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + tr.packAndPrune(); + assertEquals(2L, gc.getStatistics().numberOfPackFiles); assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); } @@ -90,13 +102,17 @@ public class GcSinceBitmapStatisticsTest extends GcTestCase { // 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); } @@ -164,4 +180,11 @@ public class GcSinceBitmapStatisticsTest extends GcTestCase { } }).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 d1342c0fbd..33cbc868ca 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.assertNull; 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 java.util.concurrent.Future; 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 class ObjectDirectoryTest extends RepositoryTestCase { .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 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 24bdc4a97a..1f934acced 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 @@ package org.eclipse.jgit.internal.storage.file; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; @@ -25,6 +26,7 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; @@ -99,6 +101,39 @@ public abstract class PackIndexTestCase extends RepositoryTestCase { } } + @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 abstract class PackIndexTestCase extends RepositoryTestCase { @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 abstract class PackIndexTestCase extends RepositoryTestCase { @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/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java index cb977bd601..acc36d76f4 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.ObjectId; 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { // 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 class RefUpdateTest extends SampleDataRepositoryTestCase { // 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 class RefUpdateTest extends SampleDataRepositoryTestCase { 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 eb521ff9eb..16645cbcd7 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.CheckoutEntry; 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 class ReflogReaderTest extends SampleDataRepositoryTestCase { 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 class ReflogReaderTest extends SampleDataRepositoryTestCase { @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(); 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 8e9b7b84bd..a8363336d9 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.File; 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 class ReflogWriterTest extends SampleDataRepositoryTestCase { 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 diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexBuilderTest.java new file mode 100644 index 0000000000..e6fefc623d --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexBuilderTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2024, GerritForge Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.midx; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader.MultiPackIndexBuilder; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader.MultiPackIndexFormatException; +import org.junit.Test; + +public class MultiPackIndexBuilderTest { + + @Test + public void testRepeatedChunk() throws Exception { + byte[] buffer = new byte[2048]; + + MultiPackIndexBuilder builder1 = MultiPackIndexBuilder.builder(); + builder1.addOidFanout(buffer); + Exception e1 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder1.addOidFanout(buffer); + }); + assertEquals("midx chunk id 0x4f494446 appears multiple times", + e1.getMessage()); + + MultiPackIndexBuilder builder2 = MultiPackIndexBuilder.builder(); + builder2.addOidLookUp(buffer); + Exception e2 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder2.addOidLookUp(buffer); + }); + assertEquals("midx chunk id 0x4f49444c appears multiple times", + e2.getMessage()); + + MultiPackIndexBuilder builder3 = MultiPackIndexBuilder.builder(); + builder3.addObjectOffsets(buffer); + Exception e3 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder3.addObjectOffsets(buffer); + }); + assertEquals("midx chunk id 0x4f4f4646 appears multiple times", + e3.getMessage()); + + MultiPackIndexBuilder builder4 = MultiPackIndexBuilder.builder(); + builder4.addPackNames(buffer); + Exception e4 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder4.addPackNames(buffer); + }); + assertEquals("midx chunk id 0x504e414d appears multiple times", + e4.getMessage()); + + MultiPackIndexBuilder builder5 = MultiPackIndexBuilder.builder(); + builder5.addBitmappedPacks(buffer); + Exception e5 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder5.addBitmappedPacks(buffer); + }); + assertEquals("midx chunk id 0x42544d50 appears multiple times", + e5.getMessage()); + + MultiPackIndexBuilder builder6 = MultiPackIndexBuilder.builder(); + builder6.addObjectLargeOffsets(buffer); + Exception e6 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder6.addObjectLargeOffsets(buffer); + }); + assertEquals("midx chunk id 0x4c4f4646 appears multiple times", + e6.getMessage()); + + MultiPackIndexBuilder builder7 = MultiPackIndexBuilder.builder(); + builder7.addReverseIndex(buffer); + Exception e7 = assertThrows(MultiPackIndexFormatException.class, () -> { + builder7.addReverseIndex(buffer); + }); + assertEquals("midx chunk id 0x52494458 appears multiple times", + e7.getMessage()); + } + + @Test + public void testNeededChunk() { + byte[] buffer = new byte[2048]; + + Exception e1 = assertThrows(MultiPackIndexFormatException.class, () -> { + MultiPackIndexBuilder.builder().addOidLookUp(buffer).build(); + }); + assertEquals("midx 0x4f494446 chunk has not been loaded", + e1.getMessage()); + + Exception e2 = assertThrows(MultiPackIndexFormatException.class, () -> { + MultiPackIndexBuilder.builder().addOidFanout(buffer) + .addOidLookUp(buffer).build(); + }); + assertEquals("midx 0x504e414d chunk has not been loaded", + e2.getMessage()); + + Exception e3 = assertThrows(MultiPackIndexFormatException.class, () -> { + MultiPackIndexBuilder.builder().addOidFanout(buffer) + .addOidLookUp(buffer).addPackNames(buffer).build(); + }); + assertEquals("midx 0x4f4f4646 chunk has not been loaded", + e3.getMessage()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java new file mode 100644 index 0000000000..494f1d1137 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024, GerritForge Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.midx; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +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.JGitTestUtil; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.junit.Test; + +/** + * Test that the loader accepts valid files, discard broken files + * <p> + * Contents and lookups are covered in the MultiPackIndexTest + */ +public class MultiPackIndexLoaderTest { + + @Test + public void load_validFile_basic_upstream() throws Exception { + MultiPackIndex midx = MultiPackIndexLoader + .open(JGitTestUtil.getTestResourceFile("multi-pack-index.v1")); + assertNotNull(midx); + } + + @Test + public void load_validFile_basic_jgit() throws Exception { + PackIndex idxOne = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000001", 500), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000005", 12), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000010", 1500))); + PackIndex idxTwo = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000002", 501), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000003", 13), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000015", 1501))); + PackIndex idxThree = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000004", 502), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000007", 14), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000012", 1502))); + + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo, "p3", + idxThree); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + assertNotNull(midx); + } + + @Test + public void load_emptyFile() { + assertThrows(IOException.class, () -> MultiPackIndexLoader + .read(new ByteArrayInputStream(new byte[0]))); + } + + @Test + public void load_rubbishFile() { + assertThrows(MultiPackIndexLoader.MultiPackIndexFormatException.class, + () -> MultiPackIndexLoader.read(new ByteArrayInputStream( + "More than 12 bytes of not-midx".getBytes(UTF_8)))); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java new file mode 100644 index 0000000000..ab452854b2 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2024, GerritForge Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.midx; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.junit.FakeIndexFactory; +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.junit.Test; + +public class MultiPackIndexTest { + + @Test + public void basic_upstream() throws IOException { + int knownPackId = 22; + int knowOffset = 258; + String knownOid = "3f4ee50f784c1e9550f09a67d2ffc1bc76917bdc"; + String knownPackName = "pack-e4b191e4343f2b7ff851026c2d8595a001077344.idx"; + String[] packNames = { + "pack-15d67b35f2b6a66ff995e09cedb36b101e0e0262.idx", + "pack-1a979514a5965e71523187a17806e03af44344ed.idx", + "pack-1de6731c035633ba8f5b41dacbc680a5a36ddd90.idx", + "pack-1ee98948e4e362c56f3cdec7f5837d06e152854f.idx", + "pack-1f6fe52ac3d33f3091d8eb8497474554bfa80bc4.idx", + "pack-34b1aa6b437a9d968412454204c2676a88dc55fa.idx", + "pack-3b245f7b4aff32a52d0520608f662bbf403792b9.idx", + "pack-47901f7f8d1c440492035c4165796a330c7f79e0.idx", + "pack-4e7f889b79aea8905a0062ce1bd68e5ef3af6a55.idx", + "pack-71ea652e4aea2cbc609545b4fbc3eda6325d88a1.idx", + "pack-723b1238411a4257c18167e91fbabed313ba332f.idx", + "pack-7bd57092a7daa4dc31277e1ec86f3de8d968ae17.idx", + "pack-883d4f469c5ea0f6d373ee623a758aeaf17715fc.idx", + "pack-8eadd378a011ddaa5ec751f2a6d9789ef501120f.idx", + "pack-92221b6f79a211944ccc6740fc22c9553ea1ba22.idx", + "pack-b139d0cae5f54c70d057a8f4d2cf99f0ae0c326c.idx", + "pack-b4f5c96d1fa6b1fac17a2a43710693c5514a9224.idx", + "pack-bed4bc1521f965e55a5a8a58dffaaefc70ea4753.idx", + "pack-cdc6baa7d90707a3c0dac4c188f797f0f79b97bb.idx", + "pack-d6d58a58fa24b74c8c082f4f63c4d2ddfb824cc9.idx", + "pack-daec59ae07f1091f3b81bd8266481bb5db3c868a.idx", + "pack-e2197d60e09ad9091407eff4e06d39ec940851e1.idx", + "pack-e4b191e4343f2b7ff851026c2d8595a001077344.idx", + "pack-eedf783b5da4caa57be33b08990fe57f245a7413.idx", + "pack-efb23e968801b9050bc70f0115a8a0eec88fb879.idx", + "pack-f919c0660c207ddf6bb0569a3041d682d19fb4f7.idx" }; + MultiPackIndex midx = MultiPackIndexLoader + .open(JGitTestUtil.getTestResourceFile("multi-pack-index.v1")); + assertNotNull(midx); + assertArrayEquals(packNames, midx.getPackNames()); + + MultiPackIndex.PackOffset oo = midx.find(ObjectId.fromString(knownOid)); + + assertEquals(knowOffset, oo.getOffset()); + assertEquals(knownPackId, oo.getPackId()); + assertEquals(knownPackName, midx.getPackNames()[oo.getPackId()]); + } + + @Test + public void basicMidx() throws IOException { + PackIndex idxOne = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000001", 500), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000005", 12), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000010", 1500))); + PackIndex idxTwo = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000002", 501), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000003", 13), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000015", 1501))); + PackIndex idxThree = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000004", 502), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000007", 14), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000012", 1502))); + + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo, "p3", + idxThree); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + assertEquals(3, midx.getPackNames().length); + assertInIndex(midx, 0, "0000000000000000000000000000000000000001", 500); + assertInIndex(midx, 0, "0000000000000000000000000000000000000005", 12); + assertInIndex(midx, 0, "0000000000000000000000000000000000000010", + 1500); + assertInIndex(midx, 1, "0000000000000000000000000000000000000002", 501); + assertInIndex(midx, 1, "0000000000000000000000000000000000000003", 13); + assertInIndex(midx, 1, "0000000000000000000000000000000000000015", + 1501); + assertInIndex(midx, 2, "0000000000000000000000000000000000000004", 502); + assertInIndex(midx, 2, "0000000000000000000000000000000000000007", 14); + assertInIndex(midx, 2, "0000000000000000000000000000000000000012", + 1502); + + assertNull(midx.find(ObjectId.zeroId())); + } + + @Test + public void jgit_largeOffsetChunk() throws IOException { + PackIndex idxOne = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000001", (1L << 34)), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000005", 12))); + PackIndex idxTwo = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000002", (1L << 35)), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000003", 13))); + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + assertEquals(2, midx.getPackNames().length); + assertInIndex(midx, 0, "0000000000000000000000000000000000000001", + (1L << 34)); + assertInIndex(midx, 0, "0000000000000000000000000000000000000005", 12); + assertInIndex(midx, 1, "0000000000000000000000000000000000000002", + (1L << 35)); + } + + @Test + public void jgit_largeOffset_noChunk() throws IOException { + // All offsets fit in 32 bits, no large offset chunk + // Most significant bit to 1 is still valid offset + PackIndex idxOne = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000001", + 0xff00_0000), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000005", 12))); + PackIndex idxTwo = FakeIndexFactory.indexOf(List.of( + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000002", 501), + new FakeIndexFactory.IndexObject( + "0000000000000000000000000000000000000003", 13))); + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + assertEquals(2, midx.getPackNames().length); + assertInIndex(midx, 0, "0000000000000000000000000000000000000001", + 0xff00_0000L); + assertInIndex(midx, 0, "0000000000000000000000000000000000000005", 12); + } + + @Test + public void jgit_resolve() throws IOException { + AbbreviatedObjectId abbrev = AbbreviatedObjectId + .fromString("32fe829a1c"); + + PackIndex idxOne = indexWith( + // Noise + "0000000000000000000000000000000000000001", + "3000000000000000000000000000000000000005", + // One before abbrev + "32fe829a1b000000000000000000000000000001", + // matches + "32fe829a1c000000000000000000000000000001", + "32fe829a1c000000000000000000000000000100", + // One after abbrev + "32fe829a1d000000000000000000000000000000"); + PackIndex idxTwo = indexWith( + // Noise + "8888880000000000000000000000000000000002", + "bbbbbb0000000000000000000000000000000003", + // Match + "32fe829a1c000000000000000000000000000010"); + + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + + + Set<ObjectId> results = new HashSet<>(); + midx.resolve(results, abbrev, 100); + + assertEquals(3, results.size()); + assertTrue(results.contains(ObjectId + .fromString("32fe829a1c000000000000000000000000000001"))); + assertTrue(results.contains(ObjectId + .fromString("32fe829a1c000000000000000000000000000010"))); + assertTrue(results.contains(ObjectId + .fromString("32fe829a1c000000000000000000000000000100"))); + + } + + @Test + public void jgit_resolve_matchLimit() throws IOException { + AbbreviatedObjectId abbrev = AbbreviatedObjectId + .fromString("32fe829a1c"); + + PackIndex idxOne = indexWith( + // Noise + "0000000000000000000000000000000000000001", + "3000000000000000000000000000000000000005", + // One before abbrev + "32fe829a1b000000000000000000000000000001", + // matches + "32fe829a1c000000000000000000000000000001", + "32fe829a1c000000000000000000000000000100", + // One after abbrev + "32fe829a1d000000000000000000000000000000"); + PackIndex idxTwo = indexWith( + // Noise + "8888880000000000000000000000000000000002", + "bbbbbb0000000000000000000000000000000003", + // Match + "32fe829a1c000000000000000000000000000010"); + + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + + + Set<ObjectId> results = new HashSet<>(); + midx.resolve(results, abbrev, 2); + + assertEquals(2, results.size()); + assertTrue(results.contains(ObjectId + .fromString("32fe829a1c000000000000000000000000000001"))); + assertTrue(results.contains(ObjectId + .fromString("32fe829a1c000000000000000000000000000010"))); + } + + @Test + public void jgit_resolve_noMatches() throws IOException { + AbbreviatedObjectId abbrev = AbbreviatedObjectId + .fromString("4400000000"); + + PackIndex idxOne = indexWith( + "0000000000000000000000000000000000000001", + "3000000000000000000000000000000000000005", + "32fe829a1b000000000000000000000000000001", + "32fe829a1c000000000000000000000000000001", + "32fe829a1c000000000000000000000000000100", + "32fe829a1d000000000000000000000000000000"); + PackIndex idxTwo = indexWith( + // Noise + "8888880000000000000000000000000000000002", + "bbbbbb0000000000000000000000000000000003", + "32fe829a1c000000000000000000000000000010"); + + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + + + Set<ObjectId> results = new HashSet<>(); + midx.resolve(results, abbrev, 200); + + assertEquals(0, results.size()); + } + + @Test + public void jgit_resolve_empty() throws IOException { + AbbreviatedObjectId abbrev = AbbreviatedObjectId + .fromString("4400000000"); + + PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); + PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); + + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + MultiPackIndex midx = MultiPackIndexLoader + .read(new ByteArrayInputStream(out.toByteArray())); + + + Set<ObjectId> results = new HashSet<>(); + midx.resolve(results, abbrev, 200); + + assertEquals(0, results.size()); + } + + private static PackIndex indexWith(String... oids) { + List<FakeIndexFactory.IndexObject> idxObjs = new ArrayList<>( + oids.length); + int offset = 12; + for (String oid : oids) { + idxObjs.add(new FakeIndexFactory.IndexObject(oid, offset)); + offset += 10; + } + return FakeIndexFactory.indexOf(idxObjs); + } + + private static void assertInIndex(MultiPackIndex midx, int expectedPackId, + String oid, long expectedOffset) { + MultiPackIndex.PackOffset packOffset = midx + .find(ObjectId.fromString(oid)); + assertNotNull(packOffset); + assertEquals("Wrong packId for " + oid, expectedPackId, + packOffset.getPackId()); + assertEquals(expectedOffset, packOffset.getOffset()); + } +} 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 0000000000..8b57a2dcb4 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java @@ -0,0 +1,179 @@ +/* + * 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.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)); + } + + @Test + public void jgit_emptyMidx() throws IOException { + PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); + PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); + Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.write(NullProgressMonitor.INSTANCE, out, packs); + List<Integer> chunkIds = readChunkIds(out); + assertEquals(1134, out.size()); + 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)); + } + + 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 0000000000..8218cbc20d --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java @@ -0,0 +1,239 @@ +/* + * 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.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 0000000000..0b3ccacfc1 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexPeekIteratorTest.java @@ -0,0 +1,71 @@ +/* + * 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.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/ReftableCompactorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java index 6fc7f25475..62dbda47fd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java @@ -19,6 +19,8 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -27,6 +29,7 @@ import org.eclipse.jgit.internal.storage.io.BlockSource; import org.eclipse.jgit.internal.storage.reftable.ReftableWriter.Stats; 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.junit.Test; @@ -279,6 +282,95 @@ public class ReftableCompactorTest { } } + @Test + public void reflog_all() throws IOException { + byte[] inTab; + try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { + ReftableWriter writer = new ReftableWriter(inBuf) + .setMinUpdateIndex(0).setMaxUpdateIndex(2).begin(); + writer.writeLog(MASTER, 2, person(Instant.ofEpochSecond(500)), + id(3), id(4), null); + writer.writeLog(MASTER, 1, person(Instant.ofEpochSecond(300)), + id(2), id(3), null); + writer.writeLog(MASTER, 0, person(Instant.ofEpochSecond(100)), + id(1), id(2), null); + writer.finish(); + inTab = inBuf.toByteArray(); + } + + ReftableCompactor compactor; + try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); + // No setReflogExpire time is set + List<ReftableReader> readers = new ArrayList<>(); + readers.add(read(inTab)); + compactor.addAll(readers); + compactor.compact(); + } + Stats stats = compactor.getStats(); + assertEquals(3, stats.logCount()); + } + + @Test + public void reflog_setExpireOlderThan() throws IOException { + byte[] inTab; + try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { + ReftableWriter writer = new ReftableWriter(inBuf) + .setMinUpdateIndex(0).setMaxUpdateIndex(2).begin(); + writer.writeLog(MASTER, 2, person(Instant.ofEpochSecond(500)), + id(3), id(4), null); + writer.writeLog(MASTER, 1, person(Instant.ofEpochSecond(300)), + id(2), id(3), null); + writer.writeLog(MASTER, 0, person(Instant.ofEpochSecond(100)), + id(1), id(2), null); + writer.finish(); + inTab = inBuf.toByteArray(); + } + + ReftableCompactor compactor; + try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); + compactor.setReflogExpireOlderThan(Instant.ofEpochSecond(300)); + List<ReftableReader> readers = new ArrayList<>(); + readers.add(read(inTab)); + compactor.addAll(readers); + compactor.compact(); + } + + Stats stats = compactor.getStats(); + assertEquals(2, stats.logCount()); + } + + @Test + public void reflog_disable() throws IOException { + byte[] inTab; + try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { + ReftableWriter writer = new ReftableWriter(inBuf) + .setMinUpdateIndex(0).setMaxUpdateIndex(2).begin(); + writer.writeLog(MASTER, 2, person(Instant.ofEpochSecond(500)), + id(3), id(4), null); + writer.writeLog(MASTER, 1, person(Instant.ofEpochSecond(300)), + id(2), id(3), null); + writer.writeLog(MASTER, 0, person(Instant.ofEpochSecond(100)), + id(1), id(2), null); + writer.finish(); + inTab = inBuf.toByteArray(); + } + + ReftableCompactor compactor; + try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); + compactor.setReflogExpireOlderThan(Instant.MAX); + List<ReftableReader> readers = new ArrayList<>(); + readers.add(read(inTab)); + compactor.addAll(readers); + compactor.compact(); + } + + Stats stats = compactor.getStats(); + assertEquals(0, stats.logCount()); + } + private static Ref ref(String name, int id) { return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id)); } @@ -296,6 +388,10 @@ public class ReftableCompactorTest { return ObjectId.fromRaw(buf); } + private static PersonIdent person(Instant when) { + return new PersonIdent("a. u. thor", "author@jgit.com", when, ZoneId.systemDefault()); + } + private static ReftableReader read(byte[] table) { return new ReftableReader(BlockSource.from(table)); } 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 ea0d92acfd..a54002bc74 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 static org.junit.Assert.fail; 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 class ReftableTest { @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 class ReftableTest { .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 class ReftableTest { .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 class ReftableTest { 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 class ReftableTest { 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 class ReftableTest { .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 class ReftableTest { @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 class ReftableTest { @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 class ReftableTest { @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 class ReftableTest { 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 924703464b..1581d49797 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.assertNull; 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 class TestRepositoryTest { 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")); @@ -294,8 +294,8 @@ public class TestRepositoryTest { 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 31940a16f7..06fee8ea71 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 class ConfigTest { 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/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java index 2b7b6ca76c..cd98606e53 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 class IndexDiffTest extends RepositoryTestCase { 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 class IndexDiffTest extends RepositoryTestCase { 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/RefDatabaseConflictingNamesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java index b02f245865..85f9612b6a 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 class RefDatabaseConflictingNamesTest { } @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 854180e3ea..a93937eeea 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.assertEquals; 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 @@ import org.junit.Test; 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 class ReflogConfigTest extends RepositoryTestCase { // 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 class ReflogConfigTest extends RepositoryTestCase { // 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 class ReflogConfigTest extends RepositoryTestCase { // 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 ae811f830f..8865ba9ebd 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.assertEquals; 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 @@ public class CherryPickTest extends RepositoryTestCase { 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 f410960bec..b1998f30f8 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.assertFalse; 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 @@ public class GitlinkMergeTest extends SampleDataRepositoryTestCase { 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/SimpleMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java index 798aebe3b0..0016adfb66 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.assertFalse; 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 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase { 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/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java index 2955516af0..014ff928a8 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 @@ -23,7 +23,9 @@ import java.io.ByteArrayOutputStream; 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 class RevCommitParseTest extends RepositoryTestCase { 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 class RevCommitParseTest extends RepositoryTestCase { 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()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCommitGraphTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCommitGraphTest.java index c2f8f10631..e47dd898b0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCommitGraphTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCommitGraphTest.java @@ -37,8 +37,9 @@ import org.eclipse.jgit.revwalk.filter.MessageRevFilter; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; +import org.eclipse.jgit.treewalk.filter.ChangedPathTreeFilter; +import org.eclipse.jgit.treewalk.filter.OrTreeFilter; import org.eclipse.jgit.treewalk.filter.PathFilter; -import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.junit.Test; @@ -172,61 +173,99 @@ public class RevWalkCommitGraphTest extends RevWalkTestCase { } @Test - public void testChangedPathFilter() throws Exception { - RevCommit c1 = commitFile("file1", "1", "master"); - commitFile("file2", "2", "master"); - RevCommit c3 = commitFile("file1", "3", "master"); - RevCommit c4 = commitFile("file2", "4", "master"); + public void testChangedPathFilter_allModify() throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file2", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file1", blob("3"))), c2); + RevCommit c4 = commit(tree(file("file2", blob("4"))), c3); + + branch(c4, "master"); enableAndWriteCommitGraph(); - TreeRevFilter trf = new TreeRevFilter(rw, PathFilter.create("file1")); + TreeRevFilter trf = new TreeRevFilter(rw, + ChangedPathTreeFilter.create("file1")); rw.markStart(rw.lookupCommit(c4)); rw.setRevFilter(trf); + assertEquals(c4, rw.next()); assertEquals(c3, rw.next()); + assertEquals(c2, rw.next()); assertEquals(c1, rw.next()); assertNull(rw.next()); - // 1 commit that has exactly one parent and matches path - assertEquals(1, trf.getChangedPathFilterTruePositive()); + // all commits modified file1 but c1 did not have a parent + assertEquals(3, trf.getChangedPathFilterTruePositive()); // No false positives assertEquals(0, trf.getChangedPathFilterFalsePositive()); - // 2 commits that have exactly one parent and don't match path - assertEquals(2, trf.getChangedPathFilterNegative()); + // No negatives because all 4 commits had modified file1 + assertEquals(0, trf.getChangedPathFilterNegative()); } @Test - public void testChangedPathFilterWithMultiPaths() throws Exception { - RevCommit c1 = commitFile("file1", "1", "master"); - RevCommit c2 = commitFile("file1", "2", "master"); - RevCommit c3 = commitFile("file2", "3", "master"); - RevCommit c4 = commitFile("file3", "4", "master"); + public void testChangedPathFilter_someModify() throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file1", blob("1"))), c1); + RevCommit c3 = commit(tree(file("file1", blob("2"))), c2); + RevCommit c4 = commit(tree(file("file1", blob("1"))), c3); + + branch(c4, "master"); enableAndWriteCommitGraph(); TreeRevFilter trf = new TreeRevFilter(rw, - PathFilterGroup.createFromStrings(List.of("file1", "file2"))); + ChangedPathTreeFilter.create("file1")); rw.markStart(rw.lookupCommit(c4)); rw.setRevFilter(trf); + assertEquals(c4, rw.next()); assertEquals(c3, rw.next()); - assertEquals(c2, rw.next()); assertEquals(c1, rw.next()); assertNull(rw.next()); - // c2 and c3 has either file1 or file2, c1 did not use ChangedPathFilter - // since it has no parent + // c4 and c3 modified file1. c1 did not have a parent assertEquals(2, trf.getChangedPathFilterTruePositive()); // No false positives assertEquals(0, trf.getChangedPathFilterFalsePositive()); - // c4 does not match either file1 or file2 + // c2 did not modify file1 assertEquals(1, trf.getChangedPathFilterNegative()); } @Test + public void testChangedPathFilterWithMultiPaths() throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file1", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file2", blob("3"))), c2); + RevCommit c4 = commit(tree(file("file3", blob("4"))), c3); + + branch(c4, "master"); + + enableAndWriteCommitGraph(); + + TreeRevFilter trf = new TreeRevFilter(rw, + ChangedPathTreeFilter.create("file1", "file2")); + rw.markStart(rw.lookupCommit(c4)); + rw.setRevFilter(trf); + assertEquals(c4, rw.next()); + assertEquals(c3, rw.next()); + assertEquals(c2, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // all commits have modified either file1 or file2, c1 did not have a + // parent + assertEquals(3, trf.getChangedPathFilterTruePositive()); + + // No false positives + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // No negative + assertEquals(0, trf.getChangedPathFilterNegative()); + } + + @Test public void testChangedPathFilterWithFollowFilter() throws Exception { RevCommit c0 = commit(tree()); RevCommit c1 = commit(tree(file("file", blob("contents"))), c0); @@ -245,9 +284,8 @@ public class RevWalkCommitGraphTest extends RevWalkTestCase { db.getConfig().setString(ConfigConstants.CONFIG_DIFF_SECTION, null, ConfigConstants.CONFIG_KEY_RENAMES, "true"); - TreeRevFilter trf = new TreeRevFilter(rw, - new FollowFilter(PathFilter.create("renamed-file"), - db.getConfig().get(DiffConfig.KEY))); + TreeRevFilter trf = new TreeRevFilter(rw, FollowFilter + .create("renamed-file", db.getConfig().get(DiffConfig.KEY))); rw.markStart(rw.lookupCommit(c4)); rw.setRevFilter(trf); assertEquals(c3, rw.next()); @@ -267,6 +305,296 @@ public class RevWalkCommitGraphTest extends RevWalkTestCase { } @Test + public void testChangedPathFilter_pathFilter_or_pathFilter_binaryOperation() + throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit( + tree(file("file1", blob("1")), file("file2", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file2", blob("2"))), c2); + RevCommit c4 = commit( + tree(file("file2", blob("2")), file("file3", blob("3"))), c3); + RevCommit c5 = commit( + tree(file("file2", blob("2")), file("file3", blob("3"))), c4); + + branch(c5, "master"); + + enableAndWriteCommitGraph(); + + ChangedPathTreeFilter pf1 = ChangedPathTreeFilter.create("file1"); + ChangedPathTreeFilter pf2 = ChangedPathTreeFilter.create("file2"); + + TreeFilter tf = OrTreeFilter + .create(new ChangedPathTreeFilter[] { pf1, pf2 }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c5)); + rw.setRevFilter(trf); + assertEquals(c3, rw.next()); + assertEquals(c2, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // c2 and c3 has either file1 or file2, c1 is not counted as + // ChangedPathFilter only applies to commits with 1 parent + assertEquals(2, trf.getChangedPathFilterTruePositive()); + + // No false positives + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // c4 and c5 did not modify file1 or file2 + assertEquals(2, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_pathFilter_or_pathFilter_or_pathFilter_listOperation() + throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit( + tree(file("file1", blob("1")), file("file2", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file2", blob("2"))), c2); + RevCommit c4 = commit(tree(file("file3", blob("3"))), c3); + RevCommit c5 = commit(tree(file("file3", blob("3"))), c4); + + branch(c5, "master"); + + enableAndWriteCommitGraph(); + + ChangedPathTreeFilter pf1 = ChangedPathTreeFilter.create("file1"); + ChangedPathTreeFilter pf2 = ChangedPathTreeFilter.create("file2"); + ChangedPathTreeFilter pf3 = ChangedPathTreeFilter.create("file3"); + + TreeFilter tf = OrTreeFilter + .create(new ChangedPathTreeFilter[] { pf1, pf2, pf3 }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c5)); + rw.setRevFilter(trf); + assertEquals(c4, rw.next()); + assertEquals(c3, rw.next()); + assertEquals(c2, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // c2 and c3 has either modified file1 or file2 or file3, c1 is not + // counted as ChangedPathFilter only applies to commits with 1 parent + assertEquals(3, trf.getChangedPathFilterTruePositive()); + + // No false positives + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // c5 does not modify either file1 or file2 or file3 + assertEquals(1, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_pathFilter_or_nonPathFilter_binaryOperation() + throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file2", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file2", blob("3"))), c2); + RevCommit c4 = commit(tree(file("file2", blob("3"))), c3); + + branch(c4, "master"); + + enableAndWriteCommitGraph(); + + ChangedPathTreeFilter pf = ChangedPathTreeFilter.create("file1"); + TreeFilter npf = TreeFilter.ANY_DIFF; + + TreeFilter tf = OrTreeFilter.create(new TreeFilter[] { pf, npf }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c4)); + rw.setRevFilter(trf); + assertEquals(c3, rw.next()); + assertEquals(c2, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // c2 modified file1, c3 defaulted positive due to ANY_DIFF, c1 is not + // counted as ChangedPathFilter only applies to commits with 1 parent + assertEquals(2, trf.getChangedPathFilterTruePositive()); + + // c4 defaulted positive due to ANY_DIFF, but didn't no diff with its + // parent c3 + assertEquals(1, trf.getChangedPathFilterFalsePositive()); + + // No negative due to the OrTreeFilter + assertEquals(0, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_nonPathFilter_or_nonPathFilter_binaryOperation() + throws Exception { + RevCommit c1 = commitFile("file1", "1", "master"); + RevCommit c2 = commitFile("file2", "2", "master"); + RevCommit c3 = commitFile("file3", "3", "master"); + RevCommit c4 = commitFile("file4", "4", "master"); + + enableAndWriteCommitGraph(); + + TreeFilter npf1 = TreeFilter.ANY_DIFF; + TreeFilter npf2 = TreeFilter.ANY_DIFF; + + TreeFilter tf = OrTreeFilter.create(new TreeFilter[] { npf1, npf2 }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c4)); + rw.setRevFilter(trf); + assertEquals(c4, rw.next()); + assertEquals(c3, rw.next()); + assertEquals(c2, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // No true positives since there's no pathFilter + assertEquals(0, trf.getChangedPathFilterTruePositive()); + + // No false positives since there's no pathFilter + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // No negative since there's no pathFilter + assertEquals(0, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_pathFilter_and_pathFilter_binaryOperation() + throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file2", blob("2"))), c1); + + branch(c2, "master"); + + enableAndWriteCommitGraph(); + + ChangedPathTreeFilter pf1 = ChangedPathTreeFilter.create("file1"); + ChangedPathTreeFilter pf2 = ChangedPathTreeFilter.create("file2"); + + TreeFilter atf = AndTreeFilter + .create(new ChangedPathTreeFilter[] { pf1, pf2 }); + TreeRevFilter trf = new TreeRevFilter(rw, atf); + + rw.markStart(rw.lookupCommit(c2)); + rw.setRevFilter(trf); + + assertNull(rw.next()); + + // c1 is not counted as ChangedPathFilter only applies to commits with 1 + // parent + assertEquals(0, trf.getChangedPathFilterTruePositive()); + + // c2 has modified both file 1 and file2, + // however nothing is returned from TreeWalk since a TreeHead + // cannot be two paths at once + assertEquals(1, trf.getChangedPathFilterFalsePositive()); + + // No negatives + assertEquals(0, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_pathFilter_and_pathFilter_and_pathFilter_listOperation() + throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file2", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file3", blob("3"))), c2); + + branch(c3, "master"); + + enableAndWriteCommitGraph(); + + ChangedPathTreeFilter pf1 = ChangedPathTreeFilter.create("file1"); + ChangedPathTreeFilter pf2 = ChangedPathTreeFilter.create("file2"); + ChangedPathTreeFilter pf3 = ChangedPathTreeFilter.create("file3"); + + TreeFilter tf = AndTreeFilter + .create(new ChangedPathTreeFilter[] { pf1, pf2, pf3 }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c3)); + rw.setRevFilter(trf); + assertNull(rw.next()); + + // c1 is not counted as ChangedPathFilter only applies to commits with 1 + // parent + assertEquals(0, trf.getChangedPathFilterTruePositive()); + + // No false positives + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // c2 and c3 can not possibly have both file1, file2, and file3 as + // treeHead at once + assertEquals(2, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_pathFilter_and_nonPathFilter_binaryOperation() + throws Exception { + RevCommit c1 = commit(tree(file("file1", blob("1")))); + RevCommit c2 = commit(tree(file("file1", blob("2"))), c1); + RevCommit c3 = commit(tree(file("file1", blob("2"))), c2); + + branch(c3, "master"); + + enableAndWriteCommitGraph(); + + ChangedPathTreeFilter pf = ChangedPathTreeFilter.create("file1"); + TreeFilter npf = TreeFilter.ANY_DIFF; + + TreeFilter tf = AndTreeFilter.create(new TreeFilter[] { pf, npf }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c3)); + rw.setRevFilter(trf); + assertEquals(c2, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // c2 modified file1 and c1 is not counted as ChangedPathFilter only + // applies to commits with 1 parent + assertEquals(1, trf.getChangedPathFilterTruePositive()); + + // No false positives + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // c3 did not modify file1 + assertEquals(1, trf.getChangedPathFilterNegative()); + } + + @Test + public void testChangedPathFilter_nonPathFilter_and_nonPathFilter_binaryOperation() + throws Exception { + RevCommit c1 = commitFile("file1", "1", "master"); + commitFile("file1", "1", "master"); + RevCommit c3 = commitFile("file3", "3", "master"); + RevCommit c4 = commitFile("file4", "4", "master"); + + enableAndWriteCommitGraph(); + + TreeFilter npf1 = TreeFilter.ANY_DIFF; + TreeFilter npf2 = TreeFilter.ANY_DIFF; + + TreeFilter tf = AndTreeFilter.create(new TreeFilter[] { npf1, npf2 }); + + TreeRevFilter trf = new TreeRevFilter(rw, tf); + rw.markStart(rw.lookupCommit(c4)); + rw.setRevFilter(trf); + assertEquals(c4, rw.next()); + assertEquals(c3, rw.next()); + assertEquals(c1, rw.next()); + assertNull(rw.next()); + + // No true positives since there's no path + assertEquals(0, trf.getChangedPathFilterTruePositive()); + + // No false positives since there's no path + assertEquals(0, trf.getChangedPathFilterFalsePositive()); + + // No negative since there's no path + assertEquals(0, trf.getChangedPathFilterNegative()); + } + + @Test public void testWalkWithCommitMessageFilter() throws Exception { RevCommit a = commit(); RevCommit b = commitBuilder().parent(a) 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 0a045c917b..ffc7c96f69 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 java.util.Arrays.asList; 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 @@ public class RevWalkUtilsReachableTest extends RevWalkTestCase { 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/SubmoduleUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java index c5e9c2deaa..d54117005d 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.File; 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 @@ import org.junit.Test; */ 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 class SubmoduleUpdateTest extends RepositoryTestCase { @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,7 +153,7 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { 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); @@ -104,8 +167,8 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { } @Test - public void repositoryWithUnconfiguredSubmodule() throws IOException, - GitAPIException { + public void repositoryWithUnconfiguredSubmodule() + throws IOException, GitAPIException { final ObjectId id = ObjectId .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); final String path = "sub"; @@ -121,16 +184,14 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { }); 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); @@ -140,8 +201,8 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { } @Test - public void repositoryWithInitializedSubmodule() throws IOException, - GitAPIException { + public void repositoryWithInitializedSubmodule() + throws IOException, GitAPIException { final ObjectId id = ObjectId .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); final String path = "sub"; @@ -168,4 +229,77 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { 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/PushCertificateStoreTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java index 4f01e4d445..a03222be0c 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 static org.junit.Assert.assertTrue; 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 class PushCertificateStoreTest { } 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 029b45e1e6..96d3a5835a 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 static org.hamcrest.MatcherAssert.assertThat; 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 class TransportHttpTest extends SampleDataRepositoryTestCase { .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 class TransportHttpTest extends SampleDataRepositoryTestCase { 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 d403624b71..67920029d4 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 class URIishTest { } @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/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index aaecfd290e..5c2f0e5c7d 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; @@ -18,6 +19,7 @@ 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; @@ -1506,14 +1508,19 @@ public class UploadPackTest { 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); @@ -1559,12 +1566,15 @@ public class UploadPackTest { 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); @@ -1601,8 +1611,9 @@ public class UploadPackTest { 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); @@ -1726,12 +1737,15 @@ public class UploadPackTest { 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); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/ChangedPathTreeFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/ChangedPathTreeFilterTest.java new file mode 100644 index 0000000000..88f6b75c6b --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/ChangedPathTreeFilterTest.java @@ -0,0 +1,122 @@ +/* + * 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.treewalk.filter; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.eclipse.jgit.internal.storage.commitgraph.ChangedPathFilter; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.filter.TreeFilter.MutableBoolean; +import org.junit.Test; + +public class ChangedPathTreeFilterTest { + + @Test + public void shouldTreeWalk_no_usingCpf() { + ChangedPathTreeFilter f = ChangedPathTreeFilter.create("a/b"); + MutableBoolean cfpUsed = new MutableBoolean(); + + boolean result = f.shouldTreeWalk(FakeRevCommit.withCpfFor("c"), null, + cfpUsed); + + assertFalse(result); + assertTrue(cfpUsed.get()); + } + + @Test + public void shouldTreeWalk_yes_usingCpf() { + ChangedPathTreeFilter f = ChangedPathTreeFilter.create("a/b"); + MutableBoolean cfpUsed = new MutableBoolean(); + + boolean result = f.shouldTreeWalk(FakeRevCommit.withCpfFor("a/b"), null, + cfpUsed); + + assertTrue(result); + assertTrue(cfpUsed.get()); + } + + @Test + public void shouldTreeWalk_yes_noCpf() { + ChangedPathTreeFilter f = ChangedPathTreeFilter.create("a/b"); + MutableBoolean cfpUsed = new MutableBoolean(); + + boolean result = f.shouldTreeWalk(FakeRevCommit.noCpf(), null, + cfpUsed); + + assertTrue(result); + assertFalse(cfpUsed.get()); + } + + @Test + public void shouldTreeWalk_no_usingCpf_noReport() { + ChangedPathTreeFilter f = ChangedPathTreeFilter.create("a/b"); + boolean result = f.shouldTreeWalk(FakeRevCommit.withCpfFor("c"), null, + null); + + assertFalse(result); + } + + @Test + public void shouldTreeWalk_yes_usingCpf_noReport() { + ChangedPathTreeFilter f = ChangedPathTreeFilter.create("a/b"); + boolean result = f.shouldTreeWalk(FakeRevCommit.withCpfFor("a/b"), null, + null); + assertTrue(result); + } + + @Test + public void shouldTreeWalk_yes_noCpf_noReport() { + ChangedPathTreeFilter f = ChangedPathTreeFilter.create("a/b"); + boolean result = f.shouldTreeWalk(FakeRevCommit.noCpf(), null, + null); + + assertTrue(result); + } + + private static class FakeRevCommit extends RevCommit { + + static RevCommit withCpfFor(String... paths) { + return new FakeRevCommit( + ChangedPathFilter.fromPaths(Arrays.stream(paths) + .map(str -> ByteBuffer.wrap(str.getBytes(UTF_8))) + .collect(Collectors.toSet()))); + } + + static RevCommit noCpf() { + return new FakeRevCommit(null); + } + + private final ChangedPathFilter cpf; + + /** + * Create a new commit reference. + * + * @param cpf + * changedPathFilter + */ + protected FakeRevCommit(ChangedPathFilter cpf) { + super(ObjectId.zeroId()); + this.cpf = cpf; + } + + @Override + public ChangedPathFilter getChangedPathFilter(RevWalk rw) { + return cpf; + } + } +}
\ No newline at end of file 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 32652494d2..44e8632228 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 @@ package org.eclipse.jgit.util; 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 class ChangeIdUtilTest { @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 class ChangeIdUtilTest { /** 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 class ChangeIdUtilTest { } @Test - public void testChangeIdAfterBugOrIssue() throws Exception { + public void testChangeIdAfterOtherFooters() throws Exception { assertEquals("a\n" + // "\n" + // "Bug: 42\n" + // @@ -541,6 +541,18 @@ public class ChangeIdUtilTest { 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 class ChangeIdUtilTest { "\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/RefMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefMapTest.java index a8077fdb0c..0c9cb2d2b0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefMapTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RefMapTest.java @@ -423,7 +423,7 @@ public class RefMapTest { Map.Entry<String, Ref> ent_b = itr.next(); assertEquals(ent_a.hashCode(), "A".hashCode()); - assertEquals(ent_a, ent_a); + assertTrue(ent_a.equals(ent_a)); assertFalse(ent_a.equals(ent_b)); assertEquals(a.toString(), ent_a.toString()); 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 015da164c3..9a1c710752 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 @@ package org.eclipse.jgit.util; 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 class StringUtilsTest { 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 423d22b748..8ee3e0197a 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF @@ -4,14 +4,14 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ui Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.jgit.awtui;version="7.2.0" -Import-Package: org.eclipse.jgit.errors;version="[7.2.0,7.3.0)", - org.eclipse.jgit.lib;version="[7.2.0,7.3.0)", - org.eclipse.jgit.nls;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revplot;version="[7.2.0,7.3.0)", - org.eclipse.jgit.revwalk;version="[7.2.0,7.3.0)", - org.eclipse.jgit.transport;version="[7.2.0,7.3.0)", - org.eclipse.jgit.util;version="[7.2.0,7.3.0)" +Export-Package: org.eclipse.jgit.awtui;version="7.4.0" +Import-Package: org.eclipse.jgit.errors;version="[7.4.0,7.5.0)", + org.eclipse.jgit.lib;version="[7.4.0,7.5.0)", + org.eclipse.jgit.nls;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revplot;version="[7.4.0,7.5.0)", + org.eclipse.jgit.revwalk;version="[7.4.0,7.5.0)", + org.eclipse.jgit.transport;version="[7.4.0,7.5.0)", + org.eclipse.jgit.util;version="[7.4.0,7.5.0)" diff --git a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF index 12363f802e..86ff12a837 100644 --- a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ui - Sources Bundle-SymbolicName: org.eclipse.jgit.ui.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ui;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ui;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index ada06ed656..0f8944be88 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.2.0-SNAPSHOT</version> + <version>7.4.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 new file mode 100644 index 0000000000..877a488a73 --- /dev/null +++ b/org.eclipse.jgit/.settings/.api_filters @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<component id="org.eclipse.jgit" version="2"> + <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.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> +</component> diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 659ad8549f..6b25c7e6f0 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -3,14 +3,14 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 7.2.0.qualifier +Bundle-Version: 7.4.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.2.0", - org.eclipse.jgit.api;version="7.2.0"; +Export-Package: org.eclipse.jgit.annotations;version="7.4.0", + org.eclipse.jgit.api;version="7.4.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.notes, org.eclipse.jgit.dircache, @@ -25,72 +25,77 @@ Export-Package: org.eclipse.jgit.annotations;version="7.2.0", org.eclipse.jgit.revwalk.filter, org.eclipse.jgit.blame, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="7.2.0"; + org.eclipse.jgit.api.errors;version="7.4.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.errors", - org.eclipse.jgit.attributes;version="7.2.0"; + org.eclipse.jgit.attributes;version="7.4.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk", - org.eclipse.jgit.blame;version="7.2.0"; + org.eclipse.jgit.blame;version="7.4.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.2.0"; + org.eclipse.jgit.blame.cache, + org.eclipse.jgit.diff, + org.eclipse.jgit.treewalk.filter", + org.eclipse.jgit.blame.cache;version="7.4.0"; + uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.diff;version="7.4.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.2.0"; + org.eclipse.jgit.dircache;version="7.4.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.2.0"; + org.eclipse.jgit.errors;version="7.4.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.2.0"; + org.eclipse.jgit.lib", + org.eclipse.jgit.events;version="7.4.0"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.fnmatch;version="7.2.0", - org.eclipse.jgit.gitrepo;version="7.2.0"; + org.eclipse.jgit.fnmatch;version="7.4.0", + org.eclipse.jgit.gitrepo;version="7.4.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.2.0";x-internal:=true, - org.eclipse.jgit.hooks;version="7.2.0";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.ignore;version="7.2.0", - org.eclipse.jgit.ignore.internal;version="7.2.0"; + org.eclipse.jgit.gitrepo.internal;version="7.4.0";x-internal:=true, + org.eclipse.jgit.hooks;version="7.4.0"; + uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.util", + org.eclipse.jgit.ignore;version="7.4.0", + org.eclipse.jgit.ignore.internal;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal;version="7.2.0"; + org.eclipse.jgit.internal;version="7.4.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.diff;version="7.2.0"; + org.eclipse.jgit.internal.diff;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.diffmergetool;version="7.2.0"; + org.eclipse.jgit.internal.diffmergetool;version="7.4.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.2.0"; + org.eclipse.jgit.internal.fsck;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.revwalk;version="7.2.0"; + org.eclipse.jgit.internal.revwalk;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.commitgraph;version="7.2.0"; + org.eclipse.jgit.internal.storage.commitgraph;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.dfs;version="7.2.0"; + org.eclipse.jgit.internal.storage.dfs;version="7.4.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.2.0"; + org.eclipse.jgit.internal.storage.file;version="7.4.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, org.eclipse.jgit.junit.http, @@ -99,41 +104,43 @@ Export-Package: org.eclipse.jgit.annotations;version="7.2.0", org.eclipse.jgit.pgm, org.eclipse.jgit.pgm.test, org.eclipse.jgit.ssh.apache", - org.eclipse.jgit.internal.storage.io;version="7.2.0"; + org.eclipse.jgit.internal.storage.io;version="7.4.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.memory;version="7.2.0"; + org.eclipse.jgit.internal.storage.memory;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.pack;version="7.2.0"; + org.eclipse.jgit.internal.storage.midx;version="7.4.0";x-internal:=true, + org.eclipse.jgit.internal.storage.pack;version="7.4.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.reftable;version="7.2.0"; + org.eclipse.jgit.internal.storage.reftable;version="7.4.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.2.0";x-internal:=true, - org.eclipse.jgit.internal.transport.connectivity;version="7.2.0"; + org.eclipse.jgit.internal.submodule;version="7.4.0";x-internal:=true, + org.eclipse.jgit.internal.transport.connectivity;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.http;version="7.2.0"; + org.eclipse.jgit.internal.transport.http;version="7.4.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.parser;version="7.2.0"; + org.eclipse.jgit.internal.transport.parser;version="7.4.0"; x-friends:="org.eclipse.jgit.http.server, org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.ssh;version="7.2.0"; + org.eclipse.jgit.internal.transport.ssh;version="7.4.0"; x-friends:="org.eclipse.jgit.ssh.apache, org.eclipse.jgit.ssh.jsch, org.eclipse.jgit.test", - org.eclipse.jgit.internal.util;version="7.2.0"; - x-friends:=" org.eclipse.jgit.junit", - org.eclipse.jgit.lib;version="7.2.0"; + org.eclipse.jgit.internal.util;version="7.4.0"; + x-friends:="org.eclipse.jgit.junit", + org.eclipse.jgit.lib;version="7.4.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 @@ Export-Package: org.eclipse.jgit.annotations;version="7.2.0", org.eclipse.jgit.util, org.eclipse.jgit.submodule, org.eclipse.jgit.util.time", - org.eclipse.jgit.lib.internal;version="7.2.0"; + org.eclipse.jgit.lib.internal;version="7.4.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.pgm, org.eclipse.egit.ui", - org.eclipse.jgit.logging;version="7.2.0", - org.eclipse.jgit.merge;version="7.2.0"; + org.eclipse.jgit.logging;version="7.4.0", + org.eclipse.jgit.merge;version="7.4.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -156,67 +163,69 @@ Export-Package: org.eclipse.jgit.annotations;version="7.2.0", org.eclipse.jgit.util, org.eclipse.jgit.api, org.eclipse.jgit.attributes", - org.eclipse.jgit.nls;version="7.2.0", - org.eclipse.jgit.notes;version="7.2.0"; + org.eclipse.jgit.nls;version="7.4.0", + org.eclipse.jgit.notes;version="7.4.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="7.2.0"; + org.eclipse.jgit.patch;version="7.4.0"; uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.revwalk, org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="7.2.0"; - uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.revwalk", - org.eclipse.jgit.revwalk;version="7.2.0"; + org.eclipse.jgit.revplot;version="7.4.0"; + uses:="org.eclipse.jgit.revwalk, + org.eclipse.jgit.lib", + org.eclipse.jgit.revwalk;version="7.4.0"; uses:="org.eclipse.jgit.lib, + org.eclipse.jgit.revwalk.filter, 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.2.0"; + org.eclipse.jgit.treewalk, + org.eclipse.jgit.internal.storage.commitgraph", + org.eclipse.jgit.revwalk.filter;version="7.4.0"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="7.2.0"; + org.eclipse.jgit.storage.file;version="7.4.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="7.2.0"; + org.eclipse.jgit.storage.pack;version="7.4.0"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="7.2.0"; + org.eclipse.jgit.submodule;version="7.4.0"; uses:="org.eclipse.jgit.lib, - org.eclipse.jgit.diff, org.eclipse.jgit.treewalk.filter, + org.eclipse.jgit.diff, org.eclipse.jgit.treewalk, org.eclipse.jgit.util", - org.eclipse.jgit.transport;version="7.2.0"; + org.eclipse.jgit.transport;version="7.4.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.2.0"; + org.eclipse.jgit.transport.http;version="7.4.0"; uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="7.2.0"; + org.eclipse.jgit.transport.resolver;version="7.4.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.lib", - org.eclipse.jgit.treewalk;version="7.2.0"; + org.eclipse.jgit.treewalk;version="7.4.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.2.0"; + org.eclipse.jgit.treewalk.filter;version="7.4.0"; uses:="org.eclipse.jgit.treewalk", - org.eclipse.jgit.util;version="7.2.0"; + org.eclipse.jgit.util;version="7.4.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.hooks, org.eclipse.jgit.revwalk, @@ -229,12 +238,12 @@ Export-Package: org.eclipse.jgit.annotations;version="7.2.0", org.eclipse.jgit.treewalk, javax.net.ssl, org.eclipse.jgit.util.time", - org.eclipse.jgit.util.io;version="7.2.0"; + org.eclipse.jgit.util.io;version="7.4.0"; uses:="org.eclipse.jgit.attributes, org.eclipse.jgit.lib, org.eclipse.jgit.treewalk", - org.eclipse.jgit.util.sha1;version="7.2.0", - org.eclipse.jgit.util.time;version="7.2.0" + org.eclipse.jgit.util.sha1;version="7.4.0", + org.eclipse.jgit.util.time;version="7.4.0" Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", javax.crypto, diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index 0f9ec1fb22..b52bd7d908 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.2.0.qualifier -Eclipse-SourceBundle: org.eclipse.jgit;version="7.2.0.qualifier";roots="." +Bundle-Version: 7.4.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit;version="7.4.0.qualifier";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index df7ae83647..ec3f314bef 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.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit</artifactId> diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index acfe812a20..e24cba6ac4 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 @@ binaryHunkDecodeError=Binary hunk, line {0}: invalid input 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 @@ branchNameInvalid=Branch name {0} is not allowed 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. @@ -161,7 +160,7 @@ commitGraphChunkNeeded=commit-graph 0x{0} chunk has not been loaded commitGraphChunkRepeated=commit-graph chunk id 0x{0} appears multiple times commitGraphChunkUnknown=unknown commit-graph chunk: 0x{0} commitGraphFileIsTooLargeForJgit=commit-graph file is too large for jgit -commitGraphUnexpectedSize=Commit-graph: expected %d bytes but out has %d bytes +commitGraphUnexpectedSize=Commit-graph: expected {0} bytes but out has {1} bytes commitGraphWritingCancelled=commit-graph writing was canceled commitMessageNotSpecified=commit message not specified commitOnRepoWithoutHEADCurrentlyNotSupported=Commit on repo without HEAD currently not supported @@ -267,6 +266,7 @@ deletingBranches=Deleting branches... 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. @@ -464,6 +464,7 @@ invalidTimestamp=Invalid timestamp in {0} 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} @@ -495,6 +496,7 @@ logInvalidDefaultCharset=System property "native.encoding" specifies unknown cha logLargerFiletimeDiff={}: inconsistent duration from file timestamps on {}, {}: diff = {} > {} (last good value). Aborting measurement. logSmallerFiletime={}: got smaller file timestamp on {}, {}: {} < {}. Aborting measurement at resolution {}. logXDGConfigHomeInvalid=Environment variable XDG_CONFIG_HOME contains an invalid path {} +logXDGCacheHomeInvalid=Environment variable XDG_CACHE_HOME contains an invalid path {} looseObjectHandleIsStale=loose-object {0} file handle is stale. retry {1} of {2} maxCountMustBeNonNegative=max count must be >= 0 mergeConflictOnNonNoteEntries=Merge conflict on non-note entries: base = {0}, ours = {1}, theirs = {2} @@ -507,6 +509,9 @@ mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b mergeToolNotGivenError=No merge tool provided and no defaults configured. mergeToolNullError=Parameter for merge tool cannot be null. messageAndTaggerNotAllowedInUnannotatedTags = Unannotated tags cannot have a message or tagger +midxChunkNeeded=midx 0x{0} chunk has not been loaded +midxChunkRepeated=midx chunk id 0x{0} appears multiple times +midxChunkUnknown=unknown midx chunk: 0x{0} minutesAgo={0} minutes ago mismatchOffset=mismatch offset for object {0} mismatchCRC=mismatch CRC for object {0} @@ -527,6 +532,10 @@ mkDirsFailed=Creating directories for {0} failed month=month months=months monthsAgo={0} months ago +multiPackIndexFileIsTooLargeForJgit=Multipack index file is too large for jgit +multiPackIndexPackCountMismatch=Multipack index: header mentions {0} packs but packfile names chunk has {1} +multiPackIndexUnexpectedSize=MultiPack index: expected {0} bytes but out has {1} 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 @@ -554,6 +563,7 @@ notACommitGraph=not a commit-graph notADIRCFile=Not a DIRC file. notAGitDirectory=not a git directory notAPACKFile=Not a PACK file. +notAMIDX=not a multi-pack-index notARef=Not a ref: {0}: {1} notASCIIString=Not ASCII string: {0} notAuthorized=not authorized @@ -615,6 +625,7 @@ peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph 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} @@ -837,7 +848,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 +unknownPositionEncoding=Unknown position encoding {0} unknownRefStorageFormat=Unknown ref storage format "{0}" unknownRepositoryFormat=Unknown repository format unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0". @@ -848,6 +859,7 @@ unmergedPath=Unmerged path: {0} unmergedPaths=Repository contains unmerged paths unpackException=Exception while parsing pack stream unreadableCommitGraph=Unreadable commit-graph: {0} +unreadableMIDX=Unreadable multi-pack-index: {0} unreadableObjectSizeIndex=Unreadable object size index. First {0} bytes are ''{1}'' unreadablePackIndex=Unreadable pack index: {0} unrecognizedPackExtension=Unrecognized pack extension: {0} @@ -861,6 +873,7 @@ unsupportedEncryptionAlgorithm=Unsupported encryption algorithm: {0} unsupportedEncryptionVersion=Unsupported encryption version: {0} unsupportedGC=Unsupported garbage collector for repository type: {0} unsupportedMark=Mark not supported +unsupportedMIDXVersion=Unsupported MIDX version {0} unsupportedObjectSizeIndexVersion=Unsupported object size index version {0} unsupportedOperationNotAddAtEnd=Not add-at-end: {0} unsupportedPackIndexVersion=Unsupported pack index version {0} 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 c895dc9aaa..b4d1cab513 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 static org.eclipse.jgit.lib.FileMode.TYPE_TREE; 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 class AddCommand extends GitCommand<DirCache> { * 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 class AddCommand extends GitCommand<DirCache> { * 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 class AddCommand extends GitCommand<DirCache> { 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 class AddCommand extends GitCommand<DirCache> { } /** - * 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 class AddCommand extends GitCommand<DirCache> { 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/DescribeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java index 805a886392..d2526287f9 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 static org.eclipse.jgit.lib.TypedConfigGetter.UNSET_INT; 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 class DescribeCommand extends GitCommand<String> { 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 class DescribeCommand extends GitCommand<String> { } } - 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 @@ public class DescribeCommand extends GitCommand<String> { }); 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 0713c38931..f24127bd51 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 @@ public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> { 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 @@ public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> { // 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 88d7e91860..f6935e1c67 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 @@ package org.eclipse.jgit.api; 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 class GarbageCollectCommand extends GitCommand<Properties> { * @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 class GarbageCollectCommand extends GitCommand<Properties> { * 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/LogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java index 555e351d32..2a8d34ed68 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java @@ -110,10 +110,10 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> { } if (!filters.isEmpty()) { if (filters.size() == 1) { - filters.add(TreeFilter.ANY_DIFF); + walk.setTreeFilter(filters.get(0)); + } else { + walk.setTreeFilter(AndTreeFilter.create(filters)); } - walk.setTreeFilter(AndTreeFilter.create(filters)); - } if (skip > -1 && maxCount > -1) walk.setRevFilter(AndRevFilter.create(SkipRevFilter.create(skip), 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 83ae0fc9d4..4b2cee45c2 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 class PullCommand extends TransportCommand<PullCommand, PullResult> { 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 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> { 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 858bd961cd..3ae7a6c81e 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.FileNotFoundException; 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 @@ public class RebaseCommand extends GitCommand<RebaseResult> { // 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 dead2749b7..a149649004 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 class ReflogCommand extends GitCommand<Collection<ReflogEntry>> { 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/StashDropCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java index 23fbe0197f..2dba0ef0f2 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 class StashDropCommand extends GitCommand<ObjectId> { 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/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java index 3524984347..5e4b2ee0b7 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.RefNotFoundException; 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.RevCommit; 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,26 +120,77 @@ public class SubmoduleUpdateCommand extends 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()); - } - CloneCommand clone = Git.cloneRepository(); - configure(clone); - clone.setURI(url); - clone.setDirectory(generator.getDirectory()); - clone.setGitDir(new File( + File gitDir = new File( new File(repo.getCommonDirectory(), Constants.MODULES), - generator.getPath())); - clone.setRelativePaths(true); - if (monitor != null) { - clone.setProgressMonitor(monitor); + 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; } - repository = clone.call().getRepository(); - } else if (this.fetch) { + } + if ((this.fetch || restored) && !cloned) { if (fetchCallback != null) { fetchCallback.fetchingSubmodule(generator.getPath()); } @@ -172,15 +227,17 @@ public class SubmoduleUpdateCommand extends 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/blame/BlameGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java index 77967df2e5..979c8cef88 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.BlobCandidate; 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 class BlameGenerator implements AutoCloseable { initRevPool(false); remaining = -1; + this.blameCache = blameCache; } private void initRevPool(boolean reverse) { @@ -159,10 +192,12 @@ public class BlameGenerator implements AutoCloseable { 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 class BlameGenerator implements AutoCloseable { } /** + * 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,7 @@ public class BlameGenerator implements AutoCloseable { Candidate n = pop(); if (n == null) return done(); + stats.candidatesVisited += 1; int pCnt = n.getParentCount(); if (pCnt == 1) { @@ -605,7 +666,7 @@ public class BlameGenerator implements AutoCloseable { // 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); @@ -695,6 +756,27 @@ public class BlameGenerator implements AutoCloseable { } } + @Nullable + private Candidate blameFromCache(Candidate n) throws IOException { + if (blameCache == null || !useCache) { + return null; + } + + List<CacheRegion> cachedBlame = blameCache.get(repository, + n.sourceCommit, n.sourcePath.getPath()); + if (cachedBlame == null) { + return null; + } + BlameRegionMerger rb = new BlameRegionMerger(repository, revPool, + cachedBlame); + Candidate fullyBlamed = rb.mergeCandidate(n); + if (fullyBlamed == null) { + return null; + } + stats.cacheHit = true; + return fullyBlamed; + } + private boolean processOne(Candidate n) throws IOException { RevCommit parent = n.getParent(0); if (parent == null) @@ -717,12 +799,17 @@ public class BlameGenerator implements AutoCloseable { if (0 == r.getOldId().prefixCompare(n.sourceBlob)) { // A 100% rename without any content change can also // skip directly to the parent. + Candidate cached = blameFromCache(n); + if (cached != null) { + return result(cached); + } n.sourceCommit = parent; n.sourcePath = PathFilter.create(r.getOldPath()); push(n); return false; } + Candidate next = n.create(getRepository(), parent, PathFilter.create(r.getOldPath())); next.sourceBlob = r.getOldId().toObjectId(); @@ -759,6 +846,11 @@ public class BlameGenerator implements AutoCloseable { return false; } + Candidate cached = blameFromCache(source); + if (cached != null) { + return result(cached); + } + parent.takeBlame(editList, source); if (parent.regionList != null) push(parent); @@ -846,8 +938,8 @@ public class BlameGenerator implements AutoCloseable { 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 +1073,10 @@ public class BlameGenerator implements AutoCloseable { /** * 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 +1090,10 @@ public class BlameGenerator implements AutoCloseable { /** * 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 +1224,39 @@ public class BlameGenerator implements AutoCloseable { 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 0000000000..67bc6fb789 --- /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/cache/BlameCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/cache/BlameCache.java new file mode 100644 index 0000000000..d44fb5f62b --- /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 0000000000..cf3f978044 --- /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/dircache/Checkout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java index accf732dc7..de02aecdb9 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 class Checkout { } } 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 34dba0b5be..c650d6e8e7 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 @@ public class DirCache { } } - 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 @@ public class DirCache { this.version = versionCode; } + /** + * @return the version code for this version + */ public int getVersionCode() { return version; } @@ -1078,6 +1086,13 @@ public class DirCache { } } + /** + * 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 class DirCache { 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 4f78404f48..18d77482e0 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.LinkedHashMap; 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.WorkingTreeOptions; 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 class DirCacheCheckout { 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 class DirCacheCheckout { * @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 class DirCacheCheckout { 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 @@ public class DirCacheCheckout { // 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 @@ public class DirCacheCheckout { // 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 @@ public class DirCacheCheckout { } 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 @@ public class DirCacheCheckout { // 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 @@ public class DirCacheCheckout { // 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 @@ public class DirCacheCheckout { // 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 @@ public class DirCacheCheckout { 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 @@ public class DirCacheCheckout { 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 @@ public class DirCacheCheckout { 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); 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 b033177e05..58b4d3dc56 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java @@ -142,7 +142,17 @@ public class ManifestParser extends DefaultHandler { xmlInRead++; final XMLReader xr; try { - xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setFeature( + "http://xml.org/sax/features/external-general-entities", //$NON-NLS-1$ + false); + spf.setFeature( + "http://xml.org/sax/features/external-parameter-entities", //$NON-NLS-1$ + false); + spf.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", //$NON-NLS-1$ + true); + xr = spf.newSAXParser().getXMLReader(); } catch (SAXException | ParserConfigurationException e) { throw new IOException(JGitText.get().noXMLParserAvailable, e); } 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 2d9d2c527c..8928f47290 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 class JGitText extends TranslationBundle { /***/ 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 class JGitText extends TranslationBundle { /***/ 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 class JGitText extends TranslationBundle { /***/ public String deleteTagUnexpectedResult; /***/ public String deletingBranches; /***/ public String deletingNotSupported; + /***/ public String deprecatedTrustFolderStat; /***/ public String depthMustBeAt1; /***/ public String depthWithUnshallow; /***/ public String destinationIsNotAWildcard; @@ -493,6 +493,7 @@ public class JGitText extends TranslationBundle { /***/ public String invalidTimeUnitValue2; /***/ public String invalidTimeUnitValue3; /***/ public String invalidTreeZeroLengthName; + /***/ public String invalidTrustStat; /***/ public String invalidURL; /***/ public String invalidWildcards; /***/ public String invalidRefSpec; @@ -525,6 +526,8 @@ public class JGitText extends TranslationBundle { /***/ public String logLargerFiletimeDiff; /***/ public String logSmallerFiletime; /***/ public String logXDGConfigHomeInvalid; + + /***/ public String logXDGCacheHomeInvalid; /***/ public String looseObjectHandleIsStale; /***/ public String maxCountMustBeNonNegative; /***/ public String mergeConflictOnNonNoteEntries; @@ -537,6 +540,9 @@ public class JGitText extends TranslationBundle { /***/ public String mergeToolNotGivenError; /***/ public String mergeToolNullError; /***/ public String messageAndTaggerNotAllowedInUnannotatedTags; + /***/ public String midxChunkNeeded; + /***/ public String midxChunkRepeated; + /***/ public String midxChunkUnknown; /***/ public String minutesAgo; /***/ public String mismatchOffset; /***/ public String mismatchCRC; @@ -557,6 +563,10 @@ public class JGitText extends TranslationBundle { /***/ public String month; /***/ public String months; /***/ public String monthsAgo; + /***/ public String multiPackIndexFileIsTooLargeForJgit; + /***/ public String multiPackIndexPackCountMismatch; + /***/ public String multiPackIndexUnexpectedSize; + /***/ public String multiPackIndexWritingCancelled; /***/ public String multipleMergeBasesFor; /***/ public String nameMustNotBeNullOrEmpty; /***/ public String need2Arguments; @@ -583,6 +593,7 @@ public class JGitText extends TranslationBundle { /***/ public String notACommitGraph; /***/ public String notADIRCFile; /***/ public String notAGitDirectory; + /***/ public String notAMIDX; /***/ public String notAPACKFile; /***/ public String notARef; /***/ public String notASCIIString; @@ -645,6 +656,7 @@ public class JGitText extends TranslationBundle { /***/ public String personIdentEmailNonNull; /***/ public String personIdentNameNonNull; /***/ public String postCommitHookFailed; + /***/ public String precedenceTrustConfig; /***/ public String prefixRemote; /***/ public String problemWithResolvingPushRefSpecsLocally; /***/ public String progressMonUploading; @@ -877,6 +889,7 @@ public class JGitText extends TranslationBundle { /***/ public String unmergedPaths; /***/ public String unpackException; /***/ public String unreadableCommitGraph; + /***/ public String unreadableMIDX; /***/ public String unreadableObjectSizeIndex; /***/ public String unreadablePackIndex; /***/ public String unrecognizedPackExtension; @@ -890,6 +903,7 @@ public class JGitText extends TranslationBundle { /***/ public String unsupportedEncryptionVersion; /***/ public String unsupportedGC; /***/ public String unsupportedMark; + /***/ public String unsupportedMIDXVersion; /***/ public String unsupportedObjectIdVersion; /***/ public String unsupportedObjectSizeIndexVersion; /***/ public String unsupportedOperationNotAddAtEnd; 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 e6068a15ec..199481cf33 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 @@ -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; @@ -352,7 +352,7 @@ public class DfsGarbageCollector { throw new IllegalStateException( JGitText.get().supportOnlyPackIndexVersion2); - startTimeMillis = SystemReader.getInstance().getCurrentTime(); + startTime = SystemReader.getInstance().now(); ctx = objdb.newReader(); try { refdb.refresh(); @@ -435,7 +435,7 @@ public class DfsGarbageCollector { 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) { @@ -723,7 +723,7 @@ public class DfsGarbageCollector { PackStatistics stats = pw.getStatistics(); pack.setPackStats(stats); - pack.setLastModified(startTimeMillis); + pack.setLastModified(startTime.toEpochMilli()); newPackDesc.add(pack); newPackStats.add(stats); newPackObj.add(pw.getObjectSet()); 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 16315bf4f2..dd9e4b96a4 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 @@ -83,7 +83,6 @@ public class DfsInserter extends ObjectInserter { DfsPackDescription packDsc; PackStream packOut; private boolean rollback; - private boolean checkExisting = true; /** * Initialize a new inserter. @@ -98,18 +97,6 @@ public class DfsInserter extends ObjectInserter { ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, -1); } - /** - * Check existence - * - * @param check - * if {@code false}, will write out possibly-duplicate objects - * without first checking whether they exist in the repo; default - * is true. - */ - public void checkExisting(boolean check) { - checkExisting = check; - } - void setCompressionLevel(int compression) { this.compression = compression; } @@ -130,8 +117,9 @@ public class DfsInserter extends ObjectInserter { if (objectMap != null && objectMap.contains(id)) return id; // Ignore unreachable (garbage) objects here. - if (checkExisting && db.has(id, true)) + if (db.has(id, true)) { return id; + } long offset = beginObject(type, len); packOut.compress.write(data, off, len); 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 efd666ff27..1a873d1204 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 @@ -52,16 +52,6 @@ public abstract class DfsObjDatabase extends ObjectDatabase { boolean dirty() { return true; } - - @Override - void clearDirty() { - // Always dirty. - } - - @Override - public void markDirty() { - // Always dirty. - } }; /** @@ -534,7 +524,7 @@ public abstract class DfsObjDatabase extends ObjectDatabase { DfsPackFile[] packs = new DfsPackFile[1 + o.packs.length]; packs[0] = newPack; System.arraycopy(o.packs, 0, packs, 1, o.packs.length); - n = new PackListImpl(packs, o.reftables); + n = new PackList(packs, o.reftables); } while (!packList.compareAndSet(o, n)); } @@ -559,7 +549,7 @@ public abstract class DfsObjDatabase extends ObjectDatabase { } } tables.add(new DfsReftable(add)); - n = new PackListImpl(o.packs, tables.toArray(new DfsReftable[0])); + n = new PackList(o.packs, tables.toArray(new DfsReftable[0])); } while (!packList.compareAndSet(o, n)); } @@ -613,13 +603,12 @@ public abstract class DfsObjDatabase extends ObjectDatabase { } if (newPacks.isEmpty() && newReftables.isEmpty()) - return new PackListImpl(NO_PACKS.packs, NO_PACKS.reftables); + return new PackList(NO_PACKS.packs, NO_PACKS.reftables); if (!foundNew) { - old.clearDirty(); return old; } Collections.sort(newReftables, reftableComparator()); - return new PackListImpl( + return new PackList( newPacks.toArray(new DfsPackFile[0]), newReftables.toArray(new DfsReftable[0])); } @@ -685,7 +674,7 @@ public abstract class DfsObjDatabase extends ObjectDatabase { } /** Snapshot of packs scanned in a single pass. */ - public abstract static class PackList { + public static class PackList { /** All known packs, sorted. */ public final DfsPackFile[] packs; @@ -715,39 +704,8 @@ public abstract class DfsObjDatabase extends ObjectDatabase { return lastModified; } - abstract boolean dirty(); - abstract void clearDirty(); - - /** - * Mark pack list as dirty. - * <p> - * Used when the caller knows that new data might have been written to the - * repository that could invalidate open readers depending on this pack list, - * for example if refs are newly scanned. - */ - public abstract void markDirty(); - } - - private static final class PackListImpl extends PackList { - private volatile boolean dirty; - - PackListImpl(DfsPackFile[] packs, DfsReftable[] reftables) { - super(packs, reftables); - } - - @Override boolean dirty() { - return dirty; - } - - @Override - void clearDirty() { - dirty = false; - } - - @Override - public void markDirty() { - dirty = true; + return false; } } 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 f9c01b9d6e..6339b0326a 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 @@ -405,7 +405,7 @@ public class DfsPackCompactor { pw.addObject(obj); obj.add(added); - src.representation(rep, id.offset, ctx, rev); + src.fillRepresentation(rep, id.offset, ctx, rev); if (rep.getFormat() != PACK_DELTA) continue; 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 48ed47a77c..05b63eaca1 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 @@ -27,6 +27,9 @@ import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.text.MessageFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -49,6 +52,7 @@ import org.eclipse.jgit.internal.storage.file.PackObjectSizeIndexLoader; import org.eclipse.jgit.internal.storage.file.PackReverseIndex; import org.eclipse.jgit.internal.storage.file.PackReverseIndexFactory; import org.eclipse.jgit.internal.storage.pack.BinaryDelta; +import org.eclipse.jgit.internal.storage.pack.ObjectToPack; import org.eclipse.jgit.internal.storage.pack.PackOutputStream; import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation; import org.eclipse.jgit.lib.AbbreviatedObjectId; @@ -59,6 +63,7 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.util.BlockList; import org.eclipse.jgit.util.LongList; /** @@ -71,6 +76,10 @@ public final class DfsPackFile extends BlockBasedFile { private static final long REF_POSITION = 0; + private static final Comparator<DfsObjectToPack> OFFSET_SORT = ( + DfsObjectToPack a, + DfsObjectToPack b) -> Long.signum(a.getOffset() - b.getOffset()); + /** * Loader for the default file-based {@link PackBitmapIndex} implementation. */ @@ -139,11 +148,15 @@ public final class DfsPackFile extends BlockBasedFile { * * @param ctx * reader to find the raw bytes + * @param idx + * primary index for this reverse index (probably loaded + * via #index(DfsReader)) * @return the reverse index of the pack * @throws IOException * a problem finding/parsing the reverse index */ - PackReverseIndex reverseIndex(DfsReader ctx) throws IOException; + PackReverseIndex reverseIndex(DfsReader ctx, PackIndex idx) + throws IOException; } /** @@ -364,7 +377,7 @@ public final class DfsPackFile extends BlockBasedFile { return reverseIndex; } - reverseIndex = indexFactory.getPackIndexes().reverseIndex(ctx); + reverseIndex = indexFactory.getPackIndexes().reverseIndex(ctx, idx(ctx)); if (reverseIndex == null) { throw new IOException( "Couldn't get a reference to the reverse index"); //$NON-NLS-1$ @@ -429,6 +442,10 @@ public final class DfsPackFile extends BlockBasedFile { return 0 < offset && !isCorrupt(offset); } + int findIdxPosition(DfsReader ctx, AnyObjectId id) throws IOException { + return idx(ctx).findPosition(id); + } + /** * Get an object from this pack. * @@ -451,23 +468,43 @@ public final class DfsPackFile extends BlockBasedFile { return idx(ctx).findOffset(id); } - void resolve(DfsReader ctx, Set<ObjectId> matches, AbbreviatedObjectId id, - int matchLimit) throws IOException { - idx(ctx).resolve(matches, id, matchLimit); - } - /** - * Obtain the total number of objects available in this pack. This method - * relies on pack index, giving number of effectively available objects. + * Return objects in the list available in this pack, sorted in (pack, + * offset) order. * * @param ctx - * current reader for the calling thread. - * @return number of objects in index of this pack, likewise in this pack + * a reader + * @param objects + * objects we are looking for + * @param skipFound + * ignore objects already found. + * @return list of objects with pack and offset set. * @throws IOException - * the index file cannot be loaded into memory. + * an error occurred */ - long getObjectCount(DfsReader ctx) throws IOException { - return idx(ctx).getObjectCount(); + List<DfsObjectToPack> findAllFromPack(DfsReader ctx, + Iterable<ObjectToPack> objects, boolean skipFound) + throws IOException { + List<DfsObjectToPack> tmp = new BlockList<>(); + for (ObjectToPack obj : objects) { + DfsObjectToPack otp = (DfsObjectToPack) obj; + if (skipFound && otp.isFound()) { + continue; + } + long p = idx(ctx).findOffset(otp); + if (p <= 0 || isCorrupt(p)) { + continue; + } + otp.setOffset(p); + tmp.add(otp); + } + Collections.sort(tmp, OFFSET_SORT); + return tmp; + } + + void resolve(DfsReader ctx, Set<ObjectId> matches, AbbreviatedObjectId id, + int matchLimit) throws IOException { + idx(ctx).resolve(matches, id, matchLimit); } private byte[] decompress(long position, int sz, DfsReader ctx) @@ -1131,31 +1168,29 @@ public final class DfsPackFile extends BlockBasedFile { /** * Return the size of the object from the object-size index. The object * should be a blob. Any other type is not indexed and returns -1. - * - * Caller MUST be sure that the object is in the pack (e.g. with - * {@link #hasObject(DfsReader, AnyObjectId)}) and the pack has object size - * index (e.g. with {@link #hasObjectSizeIndex(DfsReader)}) before asking - * the indexed size. + * <p> + * Caller MUST pass a valid index position, as returned by + * {@link #findIdxPosition(DfsReader, AnyObjectId)} and verify the pack has + * object size index (e.g. with {@link #hasObjectSizeIndex(DfsReader)}) + * before asking the indexed size. * * @param ctx * reader context to support reading from the backing store if * the object size index is not already loaded in memory. - * @param id - * object id of an object in the pack + * @param idxPosition + * position in the primary index of the object we are looking + * for, as returned by findIdxPosition * @return size of the object from the index. Negative if object is not in * the index (below threshold or not a blob) * @throws IOException * could not read the object size index. IO problem or the pack * doesn't have it. */ - long getIndexedObjectSize(DfsReader ctx, AnyObjectId id) + long getIndexedObjectSize(DfsReader ctx, int idxPosition) throws IOException { - int idxPosition = idx(ctx).findPosition(id); if (idxPosition < 0) { - throw new IllegalArgumentException( - "Cannot get size from index since object is not in pack"); //$NON-NLS-1$ + throw new IllegalArgumentException("Invalid index position"); //$NON-NLS-1$ } - PackObjectSizeIndex sizeIdx = getObjectSizeIndex(ctx); if (sizeIdx == null) { throw new IllegalStateException( @@ -1165,12 +1200,47 @@ public final class DfsPackFile extends BlockBasedFile { return sizeIdx.getSize(idxPosition); } - void representation(DfsObjectRepresentation r, final long pos, + /** + * Populates the representation object with the details of how the object at + * "pos" is stored in this pack (e.g. whole or deltified, its packed + * length). + * + * @param r + * represention object to carry data + * @param offset + * offset in this pack of the object + * @param ctx + * a reader + * @throws IOException + * an error reading the object from disk + */ + void fillRepresentation(DfsObjectRepresentation r, long offset, + DfsReader ctx) throws IOException { + fillRepresentation(r, offset, ctx, getReverseIdx(ctx)); + } + + /** + * Populates the representation object with the details of how the object at + * "pos" is stored in this pack (e.g. whole or deltified, its packed + * length). + * + * @param r + * represention object to carry data + * @param offset + * offset in this pack of the object + * @param ctx + * a reader + * @param rev + * reverse index of this pack + * @throws IOException + * an error reading the object from disk + */ + void fillRepresentation(DfsObjectRepresentation r, long offset, DfsReader ctx, PackReverseIndex rev) throws IOException { - r.offset = pos; + r.offset = offset; final byte[] ib = ctx.tempId; - readFully(pos, ib, 0, 20, ctx); + readFully(offset, ib, 0, 20, ctx); int c = ib[0] & 0xff; int p = 1; final int typeCode = (c >> 4) & 7; @@ -1178,7 +1248,7 @@ public final class DfsPackFile extends BlockBasedFile { c = ib[p++] & 0xff; } - long len = rev.findNextOffset(pos, length - 20) - pos; + long len = rev.findNextOffset(offset, length - 20) - offset; switch (typeCode) { case Constants.OBJ_COMMIT: case Constants.OBJ_TREE: @@ -1199,13 +1269,13 @@ public final class DfsPackFile extends BlockBasedFile { ofs += (c & 127); } r.format = StoredObjectRepresentation.PACK_DELTA; - r.baseId = rev.findObject(pos - ofs); + r.baseId = rev.findObject(offset - ofs); r.length = len - p; return; } case Constants.OBJ_REF_DELTA: { - readFully(pos + p, ib, 0, 20, ctx); + readFully(offset + p, ib, 0, 20, ctx); r.format = StoredObjectRepresentation.PACK_DELTA; r.baseId = ObjectId.fromRaw(ib); r.length = len - p - 20; @@ -1540,8 +1610,8 @@ public final class DfsPackFile extends BlockBasedFile { } @Override - public PackReverseIndex reverseIndex(DfsReader ctx) throws IOException { - PackIndex idx = index(ctx); + public PackReverseIndex reverseIndex(DfsReader ctx, PackIndex idx) + throws IOException { DfsStreamKey revKey = desc.getStreamKey(REVERSE_INDEX); // Keep the value parsed in the loader, in case the Ref<> is // nullified in ClockBlockCacheTable#reserveSpace 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 62f6753e5d..f50cd597e5 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 @@ -38,8 +38,6 @@ import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; import org.eclipse.jgit.internal.storage.dfs.DfsReader.PackLoadListener.DfsBlockData; import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl; import org.eclipse.jgit.internal.storage.file.PackBitmapIndex; -import org.eclipse.jgit.internal.storage.file.PackIndex; -import org.eclipse.jgit.internal.storage.file.PackReverseIndex; import org.eclipse.jgit.internal.storage.pack.CachedPack; import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs; import org.eclipse.jgit.internal.storage.pack.ObjectToPack; @@ -58,7 +56,6 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ProgressMonitor; -import org.eclipse.jgit.util.BlockList; /** * Reader to access repository content through. @@ -190,31 +187,44 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { @Override public boolean has(AnyObjectId objectId) throws IOException { + return findPack(objectId) >= 0; + } + + private int findPack(AnyObjectId objectId) throws IOException { if (last != null - && !skipGarbagePack(last) - && last.hasObject(this, objectId)) - return true; + && !skipGarbagePack(last)) { + int idxPos = last.findIdxPosition(this, objectId); + if (idxPos >= 0) { + return idxPos; + } + } + PackList packList = db.getPackList(); - if (hasImpl(packList, objectId)) { - return true; + int idxPos = findInPackList(packList, objectId); + if (idxPos >= 0) { + return idxPos; } else if (packList.dirty()) { stats.scanPacks++; - return hasImpl(db.scanPacks(packList), objectId); + idxPos = findInPackList(db.scanPacks(packList), objectId); + return idxPos; } - return false; + return -1; } - private boolean hasImpl(PackList packList, AnyObjectId objectId) + // Leave "last" pointing to the pack and return the idx position of the + // object (-1 if not found) + private int findInPackList(PackList packList, AnyObjectId objectId) throws IOException { for (DfsPackFile pack : packList.packs) { if (pack == last || skipGarbagePack(pack)) continue; - if (pack.hasObject(this, objectId)) { + int idxPos = pack.findIdxPosition(this, objectId); + if (idxPos >= 0) { last = pack; - return true; + return idxPos; } } - return false; + return -1; } @Override @@ -502,8 +512,8 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { public long getObjectSize(AnyObjectId objectId, int typeHint) throws MissingObjectException, IncorrectObjectTypeException, IOException { - DfsPackFile pack = findPackWithObject(objectId); - if (pack == null) { + int idxPos = findPack(objectId); + if (idxPos < 0) { if (typeHint == OBJ_ANY) { throw new MissingObjectException(objectId.copy(), JGitText.get().unknownObjectType2); @@ -511,16 +521,15 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { throw new MissingObjectException(objectId.copy(), typeHint); } - if (typeHint != Constants.OBJ_BLOB || !safeHasObjectSizeIndex(pack)) { - return pack.getObjectSize(this, objectId); + if (typeHint != Constants.OBJ_BLOB || !safeHasObjectSizeIndex(last)) { + return last.getObjectSize(this, objectId); } - Optional<Long> maybeSz = safeGetIndexedObjectSize(pack, objectId); - long sz = maybeSz.orElse(-1L); + long sz = safeGetIndexedObjectSize(last, idxPos); if (sz >= 0) { return sz; } - return pack.getObjectSize(this, objectId); + return last.getObjectSize(this, objectId); } @@ -528,8 +537,8 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { public boolean isNotLargerThan(AnyObjectId objectId, int typeHint, long limit) throws MissingObjectException, IncorrectObjectTypeException, IOException { - DfsPackFile pack = findPackWithObject(objectId); - if (pack == null) { + int idxPos = findPack(objectId); + if (idxPos < 0) { if (typeHint == OBJ_ANY) { throw new MissingObjectException(objectId.copy(), JGitText.get().unknownObjectType2); @@ -538,28 +547,22 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { } stats.isNotLargerThanCallCount += 1; - if (typeHint != Constants.OBJ_BLOB || !safeHasObjectSizeIndex(pack)) { - return pack.getObjectSize(this, objectId) <= limit; + if (typeHint != Constants.OBJ_BLOB || !safeHasObjectSizeIndex(last)) { + return last.getObjectSize(this, objectId) <= limit; } - Optional<Long> maybeSz = safeGetIndexedObjectSize(pack, objectId); - if (maybeSz.isEmpty()) { - // Exception in object size index - return pack.getObjectSize(this, objectId) <= limit; - } - - long sz = maybeSz.get(); + long sz = safeGetIndexedObjectSize(last, idxPos); if (sz >= 0) { return sz <= limit; } - if (isLimitInsideIndexThreshold(pack, limit)) { + if (isLimitInsideIndexThreshold(last, 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; + return last.getObjectSize(this, objectId) <= limit; } private boolean safeHasObjectSizeIndex(DfsPackFile pack) { @@ -570,21 +573,22 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { } } - private Optional<Long> safeGetIndexedObjectSize(DfsPackFile pack, - AnyObjectId objectId) { + private long safeGetIndexedObjectSize(DfsPackFile pack, + int idxPos) { long sz; try { - sz = pack.getIndexedObjectSize(this, objectId); + sz = pack.getIndexedObjectSize(this, idxPos); } catch (IOException e) { - // Do not count the exception as an index miss - return Optional.empty(); + // If there is any error in the index, we should have seen it + // on hasObjectSizeIndex. + throw new IllegalStateException(e); } if (sz < 0) { stats.objectSizeIndexMiss += 1; } else { stats.objectSizeIndexHit += 1; } - return Optional.of(sz); + return sz; } private boolean isLimitInsideIndexThreshold(DfsPackFile pack, long limit) { @@ -595,34 +599,11 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { } } - private DfsPackFile findPackWithObject(AnyObjectId objectId) - throws IOException { - if (last != null && !skipGarbagePack(last) - && last.hasObject(this, objectId)) { - return last; - } - PackList packList = db.getPackList(); - // hasImpl doesn't check "last", but leaves "last" pointing to the pack - // with the object - if (hasImpl(packList, objectId)) { - return last; - } else if (packList.dirty()) { - if (hasImpl(db.getPackList(), objectId)) { - return last; - } - } - return null; - } - @Override public DfsObjectToPack newObjectToPack(AnyObjectId objectId, int type) { return new DfsObjectToPack(objectId, type); } - private static final Comparator<DfsObjectToPack> OFFSET_SORT = ( - DfsObjectToPack a, - DfsObjectToPack b) -> Long.signum(a.getOffset() - b.getOffset()); - @Override public void selectObjectRepresentation(PackWriter packer, ProgressMonitor monitor, Iterable<ObjectToPack> objects) @@ -642,16 +623,15 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { ProgressMonitor monitor, Iterable<ObjectToPack> objects, List<DfsPackFile> packs, boolean skipFound) throws IOException { for (DfsPackFile pack : packs) { - List<DfsObjectToPack> tmp = findAllFromPack(pack, objects, skipFound); - if (tmp.isEmpty()) + List<DfsObjectToPack> inPack = pack.findAllFromPack(this, objects, skipFound); + if (inPack.isEmpty()) continue; - Collections.sort(tmp, OFFSET_SORT); - PackReverseIndex rev = pack.getReverseIdx(this); DfsObjectRepresentation rep = new DfsObjectRepresentation(pack); - for (DfsObjectToPack otp : tmp) { - pack.representation(rep, otp.getOffset(), this, rev); + for (DfsObjectToPack otp : inPack) { + // Populate rep.{offset,length} from the pack + pack.fillRepresentation(rep, otp.getOffset(), this); otp.setOffset(0); - packer.select(otp, rep); + packer.select(otp, rep); // Set otp.offset from rep if (!otp.isFound()) { otp.setFound(); monitor.update(1); @@ -698,24 +678,7 @@ public class DfsReader extends ObjectReader implements ObjectReuseAsIs { return false; } - private List<DfsObjectToPack> findAllFromPack(DfsPackFile pack, - Iterable<ObjectToPack> objects, boolean skipFound) - throws IOException { - List<DfsObjectToPack> tmp = new BlockList<>(); - PackIndex idx = pack.getPackIndex(this); - for (ObjectToPack obj : objects) { - DfsObjectToPack otp = (DfsObjectToPack) obj; - if (skipFound && otp.isFound()) { - continue; - } - long p = idx.findOffset(otp); - if (0 < p && !pack.isCorrupt(p)) { - otp.setOffset(p); - tmp.add(otp); - } - } - return tmp; - } + @Override public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp, 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 3ba74b26fc..2751cd2969 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.BatchRefUpdate; 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 class DfsReftableDatabase extends DfsRefDatabase { } @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/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java index 25b7583b95..559d5a4339 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 static org.eclipse.jgit.lib.Ref.Storage.PACKED; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -37,6 +38,7 @@ 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; @@ -70,14 +72,14 @@ public class FileReftableDatabase extends RefDatabase { private final FileReftableStack reftableStack; - FileReftableDatabase(FileRepository repo) throws IOException { - this(repo, new File(new File(repo.getCommonDirectory(), Constants.REFTABLE), - Constants.TABLES_LIST)); - } + private volatile boolean autoRefresh; - FileReftableDatabase(FileRepository repo, File refstackName) throws IOException { + FileReftableDatabase(FileRepository repo) throws IOException { this.fileRepository = repo; - this.reftableStack = new FileReftableStack(refstackName, + this.autoRefresh = repo.getConfig().getBoolean( + ConfigConstants.CONFIG_REFTABLE_SECTION, + ConfigConstants.CONFIG_KEY_AUTOREFRESH, false); + this.reftableStack = new FileReftableStack( new File(fileRepository.getCommonDirectory(), Constants.REFTABLE), () -> fileRepository.fireEvent(new RefsChangedEvent()), () -> fileRepository.getConfig()); @@ -90,7 +92,13 @@ public class FileReftableDatabase extends RefDatabase { }; } - 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); } @@ -177,6 +185,7 @@ public class FileReftableDatabase extends RefDatabase { @Override public Ref exactRef(String name) throws IOException { + autoRefresh(); return reftableDatabase.exactRef(name); } @@ -187,6 +196,7 @@ public class FileReftableDatabase extends RefDatabase { @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) { @@ -199,6 +209,7 @@ public class FileReftableDatabase extends RefDatabase { @Override public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes) throws IOException { + autoRefresh(); return reftableDatabase.getRefsByPrefixWithExclusions(include, excludes); } @@ -217,6 +228,50 @@ public class FileReftableDatabase extends RefDatabase { } + /** + * 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 = 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; + } + + private void autoRefresh() { + if (autoRefresh) { + 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()); @@ -557,9 +612,10 @@ public class FileReftableDatabase extends RefDatabase { 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); } @@ -582,10 +638,7 @@ public class FileReftableDatabase extends RefDatabase { 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()); @@ -625,32 +678,20 @@ public class FileReftableDatabase extends RefDatabase { * the repository * @param writeLogs * whether to write reflogs - * @return a reftable based RefDB from an existing repository. * @throws IOException * on IO error */ - public static FileReftableDatabase convertFrom(FileRepository repo, - boolean writeLogs) throws IOException { - FileReftableDatabase newDb = null; - File reftableList = null; - try { - File reftableDir = new File(repo.getCommonDirectory(), - Constants.REFTABLE); - reftableList = new File(reftableDir, Constants.TABLES_LIST); - if (!reftableDir.isDirectory()) { - reftableDir.mkdir(); - } + public static void convertFrom(FileRepository repo, boolean writeLogs) + throws IOException { + File reftableDir = new File(repo.getCommonDirectory(), + Constants.REFTABLE); + if (!reftableDir.isDirectory()) { + reftableDir.mkdir(); + } - try (FileReftableStack stack = new FileReftableStack(reftableList, - reftableDir, null, () -> repo.getConfig())) { - stack.addReftable(rw -> writeConvertTable(repo, rw, writeLogs)); - } - reftableList = null; - } finally { - if (reftableList != null) { - reftableList.delete(); - } + try (FileReftableStack stack = new FileReftableStack(reftableDir, null, + () -> repo.getConfig())) { + stack.addReftable(rw -> writeConvertTable(repo, rw, writeLogs)); } - return newDb; } } 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 0f5ff0f9f7..6658575fc5 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.FileInputStream; 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.Comparator; 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,9 @@ import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; 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.Constants; +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,9 +65,12 @@ public class FileReftableStack implements AutoCloseable { private List<StackEntry> stack; + private AtomicReference<FileSnapshot> snapshot = new AtomicReference<>( + FileSnapshot.DIRTY); + private long lastNextUpdateIndex; - private final File stackPath; + private final File tablesListFile; private final File reftableDir; @@ -98,11 +107,11 @@ public class FileReftableStack implements AutoCloseable { private final CompactionStats stats; + private final TrustStat trustTablesListStat; + /** * Creates a stack corresponding to the list of reftables in the argument * - * @param stackPath - * the filename for the stack. * @param reftableDir * the dir holding the tables. * @param onChange @@ -112,10 +121,10 @@ public class FileReftableStack implements AutoCloseable { * @throws IOException * on I/O problems */ - public FileReftableStack(File stackPath, File reftableDir, + public FileReftableStack(File reftableDir, @Nullable Runnable onChange, Supplier<Config> configSupplier) throws IOException { - this.stackPath = stackPath; + this.tablesListFile = new File(reftableDir, Constants.TABLES_LIST); this.reftableDir = reftableDir; this.stack = new ArrayList<>(); this.configSupplier = configSupplier; @@ -126,6 +135,8 @@ public class FileReftableStack implements AutoCloseable { reload(); stats = new CompactionStats(); + trustTablesListStat = configSupplier.get().get(CoreConfig.KEY) + .getTrustTablesListStat(); } CompactionStats getStats() { @@ -232,7 +243,7 @@ public class FileReftableStack implements AutoCloseable { } if (!success) { - throw new LockFailedException(stackPath); + throw new LockFailedException(tablesListFile); } mergedReftable = new MergedReftable(stack.stream() @@ -272,18 +283,21 @@ public class FileReftableStack implements AutoCloseable { } 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))) { + new InputStreamReader(new FileInputStream(tablesListFile), UTF_8))) { String line; while ((line = br.readLine()) != null) { if (!line.isEmpty()) { names.add(line); } } + snapshot.compareAndSet(old, FileSnapshot.save(tablesListFile)); } catch (FileNotFoundException e) { // file isn't there: empty repository. + snapshot.compareAndSet(old, FileSnapshot.MISSING_FILE); } return names; } @@ -294,9 +308,29 @@ public class FileReftableStack implements AutoCloseable { * 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(reftableDir.toPath())) { + // open the refs/reftable/ directory to refresh attributes + // of reftable files and the tables.list file listing their + // names (on some NFS clients) + } catch (FileNotFoundException | NoSuchFileException e) { + // ignore + } + //$FALL-THROUGH$ + case ALWAYS: + if (!snapshot.get().isModified(tablesListFile)) { + return true; + } + break; + case INHERIT: + // only used in CoreConfig internally + throw new IllegalStateException(); + } List<String> names = readTableNames(); if (names.size() != stack.size()) { return false; @@ -353,7 +387,7 @@ public class FileReftableStack implements AutoCloseable { */ @SuppressWarnings("nls") public boolean addReftable(Writer w) throws IOException { - LockFile lock = new LockFile(stackPath); + LockFile lock = new LockFile(tablesListFile); try { if (!lock.lockForAppend()) { return false; @@ -364,8 +398,7 @@ public class FileReftableStack implements AutoCloseable { String fn = filename(nextUpdateIndex(), nextUpdateIndex()); - File tmpTable = File.createTempFile(fn + "_", ".ref", - stackPath.getParentFile()); + File tmpTable = File.createTempFile(fn + "_", ".ref", reftableDir); ReftableWriter.Stats s; try (FileOutputStream fos = new FileOutputStream(tmpTable)) { @@ -419,7 +452,7 @@ public class FileReftableStack implements AutoCloseable { String fn = filename(first, last); File tmpTable = File.createTempFile(fn + "_", ".ref", //$NON-NLS-1$//$NON-NLS-2$ - stackPath.getParentFile()); + reftableDir); try (FileOutputStream fos = new FileOutputStream(tmpTable)) { ReftableCompactor c = new ReftableCompactor(fos) .setConfig(reftableConfig()) @@ -463,7 +496,7 @@ public class FileReftableStack implements AutoCloseable { if (first >= last) { return true; } - LockFile lock = new LockFile(stackPath); + LockFile lock = new LockFile(tablesListFile); File tmpTable = null; List<LockFile> subtableLocks = new ArrayList<>(); @@ -492,7 +525,7 @@ public class FileReftableStack implements AutoCloseable { tmpTable = compactLocked(first, last); - lock = new LockFile(stackPath); + lock = new LockFile(tablesListFile); if (!lock.lock()) { 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 c5c36565d9..bcf9f1efdf 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 @@ -31,7 +31,6 @@ import java.util.Locale; 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; @@ -543,29 +542,6 @@ public class FileRepository extends Repository { } @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); } @@ -697,8 +673,8 @@ public class FileRepository extends Repository { } 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); @@ -743,6 +719,8 @@ public class FileRepository extends Repository { } 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(); } 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 7f3369364b..c08a92e5a7 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 @@ -102,7 +102,7 @@ import org.eclipse.jgit.treewalk.filter.TreeFilter; 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; @@ -160,11 +160,11 @@ public class GC { private long expireAgeMillis = -1; - private Date expire; + private Instant expire; private long packExpireAgeMillis = -1; - private Date packExpire; + private Instant packExpire; private Boolean packKeptObjects; @@ -183,7 +183,7 @@ public class GC { * prune() to inspect only those reflog entries which have been added since * last repack(). */ - private long lastRepackTime; + private Instant lastRepackTime; /** * Whether gc should do automatic housekeeping @@ -698,16 +698,18 @@ public class GC { 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; } @@ -724,16 +726,18 @@ public class GC { 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; } @@ -802,7 +806,7 @@ public class GC { public Collection<Pack> repack() throws IOException { Collection<Pack> toBeDeleted = repo.getObjectDatabase().getPacks(); - long time = System.currentTimeMillis(); + Instant time = SystemReader.getInstance().now(); Collection<Ref> refsBefore = getAllRefs(); Set<ObjectId> allHeadsAndTags = new HashSet<>(); @@ -818,7 +822,7 @@ public class GC { for (Ref ref : refsBefore) { checkCancelled(); - nonHeads.addAll(listRefLogObjects(ref, 0)); + nonHeads.addAll(listRefLogObjects(ref, Instant.EPOCH)); if (ref.isSymbolic() || ref.getObjectId() == null) { continue; } @@ -1148,21 +1152,23 @@ public class GC { * @param ref * the ref which log should be inspected * @param minTime - * only reflog entries not older then this time are processed + * only reflog entries equal or younger than this time are + * processed * @return the {@link ObjectId}s contained in the reflog * @throws IOException * if an IO error occurred */ - private Set<ObjectId> listRefLogObjects(Ref ref, long minTime) throws IOException { - ReflogReader reflogReader = repo.getReflogReader(ref); + private Set<ObjectId> listRefLogObjects(Ref ref, Instant minTime) throws IOException { + ReflogReader reflogReader = repo.getRefDatabase().getReflogReader(ref); List<ReflogEntry> rlEntries = reflogReader .getReverseEntries(); if (rlEntries == null || rlEntries.isEmpty()) return Collections.emptySet(); Set<ObjectId> ret = new HashSet<>(); for (ReflogEntry e : rlEntries) { - if (e.getWho().getWhen().getTime() < minTime) + if (e.getWho().getWhenAsInstant().isBefore(minTime)) { break; + } ObjectId newId = e.getNewId(); if (newId != null && !ObjectId.zeroId().equals(newId)) ret.add(newId); @@ -1548,7 +1554,7 @@ public class GC { public RepoStatistics getStatistics() throws IOException { RepoStatistics ret = new RepoStatistics(); Collection<Pack> packs = repo.getObjectDatabase().getPacks(); - long latestBitmapTime = Long.MIN_VALUE; + long latestBitmapTime = 0L; for (Pack p : packs) { long packedObjects = p.getIndex().getObjectCount(); ret.numberOfPackedObjects += packedObjects; @@ -1556,9 +1562,11 @@ public class GC { ret.sizeOfPackedObjects += p.getPackFile().length(); if (p.getBitmapIndex() != null) { ret.numberOfBitmaps += p.getBitmapIndex().getBitmapCount(); - latestBitmapTime = p.getFileSnapshot().lastModifiedInstant() - .toEpochMilli(); - } else { + if (latestBitmapTime == 0L) { + latestBitmapTime = p.getFileSnapshot().lastModifiedInstant().toEpochMilli(); + } + } + else if (latestBitmapTime == 0L) { ret.numberOfPackFilesSinceBitmap++; ret.numberOfObjectsSinceBitmap += packedObjects; } @@ -1655,12 +1663,31 @@ public class GC { * 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; } @@ -1673,8 +1700,24 @@ public class GC { * * @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 8647b3e664..862aaab0ee 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 java.time.Instant; 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}. @@ -62,8 +61,7 @@ class GcLog { 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/LooseObjects.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LooseObjects.java index b4bb2a9293..909b3e3082 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.internal.storage.file.FileObjectDatabase.InsertLooseObje 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 @@ class LooseObjects { */ 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 @@ class LooseObjects { } 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 @@ class LooseObjects { } 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 @@ class LooseObjects { 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 @@ class LooseObjects { 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/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java index 9f21481a13..3a6de4e8e2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java @@ -200,6 +200,7 @@ public class ObjectDirectory extends FileObjectDatabase { loose.close(); packed.close(); + preserved.close(); // Fully close all loaded alternates and clear the alternate list. AlternateHandle[] alt = alternates.get(); 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 8d2a86386f..5813d39e9a 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,7 +116,7 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { private volatile Exception invalidatingCause; @Nullable - private PackFile bitmapIdxFile; + private volatile PackFile bitmapIdxFile; private AtomicInteger transientErrorCount = new AtomicInteger(); @@ -645,42 +648,53 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { 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(); + private void endCopyAsIs() { + synchronized (activeLock) { + if (--activeCopyRawData == 0 && activeWindows == 0) { + doClose(); + } + } } - synchronized boolean beginWindowCache() throws IOException { - if (++activeWindows == 1) { - if (activeCopyRawData == 0) - doOpen(); - return true; + boolean beginWindowCache() throws IOException { + synchronized (activeLock) { + if (++activeWindows == 1) { + if (activeCopyRawData == 0) { + doOpen(); + } + return true; + } + return false; } - return false; } - synchronized boolean endWindowCache() { - final boolean r = --activeWindows == 0; - if (r && activeCopyRawData == 0) - doClose(); - return r; + 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 { @@ -691,39 +705,41 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { } } 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(); } @@ -1197,17 +1213,8 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { 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 e31126f027..f50c17eafa 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 static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; 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; @@ -42,7 +44,8 @@ import org.eclipse.jgit.internal.storage.pack.PackWriter; 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; @@ -72,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. @@ -86,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(); } /** @@ -313,38 +309,42 @@ class PackDirectory { } 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); } @@ -361,8 +361,26 @@ class PackDirectory { } 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) { @@ -459,12 +477,9 @@ class PackDirectory { && !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; } 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 c9b05ad025..5f2015b834 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 @@ -185,7 +185,11 @@ public class PackFile extends File { private static PackExt getPackExt(String endsWithExtension) { for (PackExt ext : PackExt.values()) { - if (endsWithExtension.endsWith(ext.getExtension())) { + if (endsWithExtension.equals(ext.getExtension())) { + return ext; + } + + if (endsWithExtension.equals("old-" + ext.getExtension())) { return 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 7189ce20a6..b3e4efb4fc 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 @@ -286,7 +286,7 @@ public interface PackIndex * the index cannot be read. */ void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, - int matchLimit) throws IOException; + int matchLimit) throws IOException; /** * Get pack checksum @@ -304,6 +304,7 @@ public interface PackIndex 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; @@ -345,6 +346,34 @@ public interface PackIndex r.offset = offset; return r; } + + /** + * 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); + } } /** @@ -368,7 +397,6 @@ public interface PackIndex this.objectCount = objectCount; } - @Override public boolean hasNext() { return returnedNumber < objectCount; @@ -393,7 +421,6 @@ public interface PackIndex */ protected abstract void readNext(); - /** * Copies to the entry an {@link ObjectId} from the int buffer and * position idx @@ -423,7 +450,8 @@ public interface PackIndex /** * Sets the {@code offset} to the entry * - * @param offset the offset in the pack file + * @param offset + * the offset in the pack file */ protected void setOffset(long offset) { entry.offset = offset; 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 6aa1157e37..319a9ed710 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 @@ -64,10 +64,9 @@ 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; @@ -76,6 +75,7 @@ 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; @@ -184,11 +184,7 @@ 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; @@ -200,9 +196,7 @@ public class RefDirectory extends RefDatabase { 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; } @@ -218,17 +212,7 @@ public class RefDirectory extends RefDatabase { looseRefs.set(RefList.<LooseRef> emptyList()); packedRefs.set(NO_PACKED_REFS); - trustFolderStat = db.getConfig() - .getBoolean(ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true); - trustPackedRefsStat = db.getConfig() - .getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_TRUST_PACKED_REFS_STAT, - TrustPackedRefsStat.UNSET); - 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); } @@ -456,6 +440,11 @@ public class RefDirectory extends RefDatabase { 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; @@ -712,41 +701,47 @@ public class RefDirectory extends RefDatabase { } String name = dst.getName(); - // Write the packed-refs file using an atomic update. We might - // wind up reading it twice, before and after the lock, to ensure - // we don't miss an edit made externally. - PackedRefList packed = getPackedRefs(); - if (packed.contains(name)) { - inProcessPackedRefsLock.lock(); + // Get and keep the packed-refs lock while updating packed-refs and + // removing any loose ref + inProcessPackedRefsLock.lock(); + try { + LockFile lck = lockPackedRefsOrThrow(); try { - LockFile lck = lockPackedRefsOrThrow(); - try { + // Write the packed-refs file using an atomic update. We might + // wind up reading it twice, before and after checking if the + // ref to delete is included or not, to ensure + // we don't rely on a PackedRefList that is a result of in-memory + // or NFS caching. + PackedRefList packed = getPackedRefs(); + if (packed.contains(name)) { + // Force update our packed-refs snapshot before writing packed = refreshPackedRefs(); int idx = packed.find(name); if (0 <= idx) { commitPackedRefs(lck, packed.remove(idx), packed, true); } - } finally { - lck.unlock(); } - } finally { - inProcessPackedRefsLock.unlock(); - } - } - RefList<LooseRef> curLoose, newLoose; - do { - curLoose = looseRefs.get(); - int idx = curLoose.find(name); - if (idx < 0) - break; - newLoose = curLoose.remove(idx); - } while (!looseRefs.compareAndSet(curLoose, newLoose)); + RefList<LooseRef> curLoose, newLoose; + do { + curLoose = looseRefs.get(); + int idx = curLoose.find(name); + if (idx < 0) { + break; + } + newLoose = curLoose.remove(idx); + } while (!looseRefs.compareAndSet(curLoose, newLoose)); - int levels = levelsIn(name) - 2; - delete(logFor(name), levels); - if (dst.getStorage().isLoose()) { - deleteAndUnlock(fileFor(name), levels, update); + int levels = levelsIn(name) - 2; + delete(logFor(name), levels); + if (dst.getStorage().isLoose()) { + deleteAndUnlock(fileFor(name), levels, update); + } + } finally { + lck.unlock(); + } + } finally { + inProcessPackedRefsLock.unlock(); } modCnt.incrementAndGet(); @@ -973,7 +968,7 @@ public class RefDirectory extends RefDatabase { PackedRefList getPackedRefs() throws IOException { final PackedRefList curList = packedRefs.get(); - switch (trustPackedRefsStat) { + switch (coreConfig.getTrustPackedRefsStat()) { case NEVER: break; case AFTER_OPEN: @@ -989,12 +984,8 @@ public class RefDirectory extends RefDatabase { return curList; } break; - case UNSET: - if (trustFolderStat - && !curList.snapshot.isModified(packedRefsFile)) { - return curList; - } - break; + case INHERIT: + // only used in CoreConfig internally } return refreshPackedRefs(curList); @@ -1180,7 +1171,7 @@ public class RefDirectory extends RefDatabase { 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)); } 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 fd80faf4ed..15c125c684 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 @@ -790,7 +790,9 @@ public class WindowCache { } numRemovers++; } - for (int numRemoved = 0; removeNextBlock(numRemoved); numRemoved++); + for (int numRemoved = 0; removeNextBlock(numRemoved); numRemoved++) { + // empty + } synchronized (this) { if (numRemovers > 0) { numRemovers--; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java new file mode 100644 index 0000000000..15b52391b8 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2024, GerritForge Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.midx; + +import java.util.Set; + +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; + +/** + * An index over multiple packs + */ +public interface MultiPackIndex { + + /** + * Obtain the array of packfiles in the MultiPackIndex. + * <p> + * The pack ids correspond to positions in this list. + * + * @return array of packnames refered in this multipak index + */ + String[] getPackNames(); + + /** + * Does this index contains the object + * + * @param oid + * object id + * @return true of the index knows this the object + */ + boolean hasObject(AnyObjectId oid); + + /** + * Obtain the location of the object. + * <p> + * The returned object can be reused by the implementations. Callers + * must create a #copy() if they want to keep a reference. + * + * @param objectId + * objectId to read. + * @return mutable instance with the location or null if not found. + */ + PackOffset find(AnyObjectId objectId); + + /** + * Find objects matching the prefix abbreviation. + * + * @param matches + * set to add any located ObjectIds to. This is an output + * parameter. + * @param id + * prefix to search for. + * @param matchLimit + * maximum number of results to return. At most this many + * ObjectIds should be added to matches before returning. + */ + void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, int matchLimit); + + /** + * Memory size of this multipack index + * + * @return size of this multipack index in memory, in bytes + */ + long getMemorySize(); + + /** + * (packId, offset) coordinates of an object + */ + class PackOffset { + + int packId; + + long offset; + + protected PackOffset setValues(int packId, long offset) { + this.packId = packId; + this.offset = offset; + return this; + } + + public int getPackId() { + return packId; + } + + public long getOffset() { + return offset; + } + + public PackOffset copy() { + PackOffset copy = new PackOffset(); + return copy.setValues(this.packId, this.offset); + } + } +} 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 0000000000..5d86f44baf --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexConstants.java @@ -0,0 +1,58 @@ +/* + * 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.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; + + /** "BTMP" chunk */ + static final int MIDX_CHUNKID_BITMAPPEDPACKS = 0x42544D50; + + private MultiPackIndexConstants() { + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java new file mode 100644 index 0000000000..61caddc221 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoader.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2024, GerritForge Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.midx; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_BITMAPPEDPACKS; +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.lib.Constants.OBJECT_ID_LENGTH; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.NB; +import org.eclipse.jgit.util.io.SilentFileInputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The loader returns the representation of the MultiPackIndex file content. + */ +public class MultiPackIndexLoader { + private final static Logger LOG = LoggerFactory + .getLogger(MultiPackIndexLoader.class); + + /** + * Open an existing MultiPackIndex file for reading. + * <p> + * The format of the file will be automatically detected and a proper access + * implementation for that format will be constructed and returned to the + * caller. The file may or may not be held open by the returned instance. + * + * @param midxFile + * existing multi-pack-index to read. + * @return a copy of the multi-pack-index file in memory + * @throws FileNotFoundException + * the file does not exist. + * @throws MultiPackIndexFormatException + * MultiPackIndex file's format is different from we expected. + * @throws java.io.IOException + * the file exists but could not be read due to security errors + * or unexpected data corruption. + */ + public static MultiPackIndex open(File midxFile) + throws FileNotFoundException, MultiPackIndexFormatException, + IOException { + try (SilentFileInputStream fd = new SilentFileInputStream(midxFile)) { + try { + return read(fd); + } catch (MultiPackIndexFormatException fe) { + throw fe; + } catch (IOException ioe) { + throw new IOException( + MessageFormat.format(JGitText.get().unreadableMIDX, + midxFile.getAbsolutePath()), + ioe); + } + } + } + + /** + * Read an existing MultiPackIndex file from a buffered stream. + * <p> + * The format of the file will be automatically detected and a proper access + * implementation for that format will be constructed and returned to the + * caller. The file may or may not be held open by the returned instance. + * + * @param fd + * stream to read the multipack-index file from. The stream must be + * buffered as some small IOs are performed against the stream. + * The caller is responsible for closing the stream. + * @return a copy of the MultiPackIndex file in memory + * @throws MultiPackIndexFormatException + * the MultiPackIndex file's format is different from we + * expected. + * @throws java.io.IOException + * the stream cannot be read. + */ + public static MultiPackIndex read(InputStream fd) + throws MultiPackIndexFormatException, IOException { + byte[] hdr = new byte[12]; + IO.readFully(fd, hdr, 0, hdr.length); + + int magic = NB.decodeInt32(hdr, 0); + + if (magic != MIDX_SIGNATURE) { + throw new MultiPackIndexFormatException(JGitText.get().notAMIDX); + } + + // Check MultiPackIndex version + int v = hdr[4]; + if (v != 1) { + throw new MultiPackIndexFormatException(MessageFormat + .format(JGitText.get().unsupportedMIDXVersion, v)); + } + + // Read the object Id version (1 byte) + // 1 => SHA-1 + // 2 => SHA-256 + // TODO: If the hash type does not match the repository's hash + // algorithm, + // the multi-pack-index file should be ignored with a warning + // presented to the user. + int commitIdVersion = hdr[5]; + if (commitIdVersion != 1) { + throw new MultiPackIndexFormatException( + JGitText.get().incorrectOBJECT_ID_LENGTH); + } + + // Read the number of "chunkOffsets" (1 byte) + int chunkCount = hdr[6]; + + // Read the number of multi-pack-index files (1 byte) + // This value is currently always zero. + // TODO populate this + // int numberOfMultiPackIndexFiles = hdr[7]; + + // Number of packfiles (4 bytes) + int packCount = NB.decodeInt32(hdr, 8); + + byte[] lookupBuffer = new byte[CHUNK_LOOKUP_WIDTH * (chunkCount + 1)]; + + IO.readFully(fd, 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)); + } + + MultiPackIndexBuilder builder = MultiPackIndexBuilder.builder(); + builder.setPackCount(packCount); + for (int i = 0; i < chunkCount; i++) { + long chunkOffset = chunks.get(i).offset; + int chunkId = chunks.get(i).id; + long len = chunks.get(i + 1).offset - chunkOffset; + + if (len > Integer.MAX_VALUE - 8) { // http://stackoverflow.com/a/8381338 + throw new MultiPackIndexFormatException( + JGitText.get().multiPackIndexFileIsTooLargeForJgit); + } + + byte[] buffer = new byte[(int) len]; + IO.readFully(fd, buffer, 0, buffer.length); + + switch (chunkId) { + case MIDX_CHUNKID_OIDFANOUT: + builder.addOidFanout(buffer); + break; + case MIDX_CHUNKID_OIDLOOKUP: + builder.addOidLookUp(buffer); + break; + case MIDX_CHUNKID_PACKNAMES: + builder.addPackNames(buffer); + break; + case MIDX_CHUNKID_BITMAPPEDPACKS: + builder.addBitmappedPacks(buffer); + break; + case MIDX_CHUNKID_OBJECTOFFSETS: + builder.addObjectOffsets(buffer); + break; + case MIDX_CHUNKID_LARGEOFFSETS: + builder.addObjectLargeOffsets(buffer); + break; + default: + LOG.warn(MessageFormat.format(JGitText.get().midxChunkUnknown, + Integer.toHexString(chunkId))); + } + } + return builder.build(); + } + + private record ChunkSegment(int id, long offset) {} + + /** + * Accumulate byte[] of the different chunks, to build a multipack index + */ + // Visible for testing + static class MultiPackIndexBuilder { + + private final int hashLength; + + private int packCount; + + private byte[] oidFanout; + + private byte[] oidLookup; + + private String[] packNames; + + private byte[] bitmappedPackfiles; + + private byte[] objectOffsets; + + // Optional + private byte[] largeObjectOffsets; + + // Optional + private byte[] bitmapPackOrder; + + private MultiPackIndexBuilder(int hashLength) { + this.hashLength = hashLength; + } + + /** + * Create builder + * + * @return A builder of {@link MultiPackIndex}. + */ + static MultiPackIndexBuilder builder() { + return new MultiPackIndexBuilder(OBJECT_ID_LENGTH); + } + + MultiPackIndexBuilder setPackCount(int packCount) { + this.packCount = packCount; + return this; + } + + MultiPackIndexBuilder addOidFanout(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(oidFanout, MIDX_CHUNKID_OIDFANOUT); + oidFanout = buffer; + return this; + } + + MultiPackIndexBuilder addOidLookUp(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(oidLookup, MIDX_CHUNKID_OIDLOOKUP); + oidLookup = buffer; + return this; + } + + MultiPackIndexBuilder addPackNames(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(packNames, MIDX_CHUNKID_PACKNAMES); + packNames = new String(buffer, UTF_8).split("\u0000"); //$NON-NLS-1$ + return this; + } + + MultiPackIndexBuilder addBitmappedPacks(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(bitmappedPackfiles, + MIDX_CHUNKID_BITMAPPEDPACKS); + bitmappedPackfiles = buffer; + return this; + } + + MultiPackIndexBuilder addObjectOffsets(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(objectOffsets, MIDX_CHUNKID_OBJECTOFFSETS); + objectOffsets = buffer; + return this; + } + + MultiPackIndexBuilder addObjectLargeOffsets(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(largeObjectOffsets, + MIDX_CHUNKID_LARGEOFFSETS); + largeObjectOffsets = buffer; + return this; + } + + MultiPackIndexBuilder addReverseIndex(byte[] buffer) + throws MultiPackIndexFormatException { + assertChunkNotSeenYet(bitmapPackOrder, MIDX_CHUNKID_REVINDEX); + bitmapPackOrder = buffer; + return this; + } + + MultiPackIndex build() throws MultiPackIndexFormatException { + assertChunkNotNull(oidFanout, MIDX_CHUNKID_OIDFANOUT); + assertChunkNotNull(oidLookup, MIDX_CHUNKID_OIDLOOKUP); + assertChunkNotNull(packNames, MIDX_CHUNKID_PACKNAMES); + assertChunkNotNull(objectOffsets, MIDX_CHUNKID_OBJECTOFFSETS); + + assertPackCounts(packCount, packNames.length); + return new MultiPackIndexV1(hashLength, oidFanout, oidLookup, + packNames, bitmappedPackfiles, objectOffsets, largeObjectOffsets); + } + + private static void assertChunkNotNull(Object object, int chunkId) + throws MultiPackIndexFormatException { + if (object == null) { + throw new MultiPackIndexFormatException( + MessageFormat.format(JGitText.get().midxChunkNeeded, + Integer.toHexString(chunkId))); + } + } + + private static void assertChunkNotSeenYet(Object object, int chunkId) + throws MultiPackIndexFormatException { + if (object != null) { + throw new MultiPackIndexFormatException( + MessageFormat.format(JGitText.get().midxChunkRepeated, + Integer.toHexString(chunkId))); + } + } + + private static void assertPackCounts(int headerCount, + int packfileNamesCount) throws MultiPackIndexFormatException { + if (headerCount != packfileNamesCount) { + throw new MultiPackIndexFormatException(MessageFormat.format( + JGitText.get().multiPackIndexPackCountMismatch, + headerCount, packfileNamesCount)); + } + } + } + + /** + * Thrown when a MultiPackIndex file's format is different from we expected + */ + public static class MultiPackIndexFormatException extends IOException { + + private static final long serialVersionUID = 1L; + + /** + * Construct an exception. + * + * @param why + * description of the type of error. + */ + MultiPackIndexFormatException(String why) { + super(why); + } + } +} 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 0000000000..948b7bc174 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexPrettyPrinter.java @@ -0,0 +1,156 @@ +/* + * 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.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/MultiPackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexV1.java new file mode 100644 index 0000000000..be752cc4b5 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexV1.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2024, GerritForge Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.midx; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Set; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader.MultiPackIndexFormatException; +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.util.NB; + +/** + * Support for the MultiPackIndex v1 format. + * + * @see MultiPackIndex + */ +class MultiPackIndexV1 implements MultiPackIndex { + + private final OidLookup idx; + + private final String[] packNames; + + private final byte[] bitmappedPackfiles; + + private final OffsetLookup offsets; + + private final PackOffset result = new PackOffset(); + + MultiPackIndexV1(int hashLength, @NonNull byte[] oidFanout, + @NonNull byte[] oidLookup, String[] packNames, + byte[] bitmappedPackfiles, byte[] objectOffsets, + byte[] largeObjectOffsets) throws MultiPackIndexFormatException { + this.bitmappedPackfiles = bitmappedPackfiles; + this.idx = new OidLookup(hashLength, oidFanout, oidLookup); + this.offsets = new OffsetLookup(objectOffsets, largeObjectOffsets); + this.packNames = packNames; + } + + @Override + public String[] getPackNames() { + return packNames; + } + + @Override + public boolean hasObject(AnyObjectId oid) { + return idx.findMultiPackIndexPosition(oid) != -1; + } + + @Override + @Nullable + public PackOffset find(AnyObjectId objectId) { + int position = idx.findMultiPackIndexPosition(objectId); + if (position == -1) { + return null; + } + offsets.getObjectOffset(position, result); + return result; + } + + @Override + public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, + int matchLimit) { + idx.resolve(matches, id, matchLimit); + } + + @Override + public long getMemorySize() { + int packNamesSize = Arrays.stream(packNames) + .mapToInt(s -> s.getBytes(StandardCharsets.UTF_8).length).sum(); + return packNamesSize + byteArrayLengh(bitmappedPackfiles) + + idx.getMemorySize() + offsets.getMemorySize(); + } + + @Override + public String toString() { + return "MultiPackIndexV1 {idx=" + idx + ", packfileNames=" //$NON-NLS-1$ //$NON-NLS-2$ + + Arrays.toString(packNames) + ", bitmappedPackfiles=" //$NON-NLS-1$ + + byteArrayToString(bitmappedPackfiles) + ", objectOffsets=" //$NON-NLS-1$ + + offsets + '}'; + } + + private static String byteArrayToString(byte[] array) { + return array == null ? "null" : new String(array); //$NON-NLS-1$ + } + + private static int byteArrayLengh(byte[] array) { + return array == null ? 0 : array.length; + } + + /** + * Wraps the small and large offset chunks (if exists), to lookup offsets. + */ + private static class OffsetLookup { + private static final int OBJECT_OFFSETS_DATA_WIDTH = 8; + + private static final int BIT_31_ON = 0x80000000; + + private static final int TOGGLE_BIT_31 = 0x7fff_ffff; + + private final byte[] offsets; + + private final byte[] largeOffsets; + + /** + * Initialize the ObjectOffsets. + * + * @param offsets + * content of ObjectOffset Chunk. + * @param largeOffsets + * content of largo offsets chunks (can be null). + */ + OffsetLookup(@NonNull byte[] offsets, byte[] largeOffsets) { + this.offsets = offsets; + this.largeOffsets = largeOffsets; + } + + /** + * Get the metadata of a commit。 + * + * @param position + * the position in the multi-pack-index of the object. + * @param result + * an instance of PackOffset to populate with the result. + */ + void getObjectOffset(int position, PackOffset result) { + int offsetInChunk = position * OBJECT_OFFSETS_DATA_WIDTH; + int packId = NB.decodeInt32(offsets, offsetInChunk); + int offset = NB.decodeInt32(offsets, offsetInChunk + 4); + if ((offset & BIT_31_ON) != 0) { + long bigOffset; + if (largeOffsets == null) { + bigOffset = NB.decodeUInt32(offsets, offsetInChunk + 4); + } else { + int bigOffsetPos = (offset & TOGGLE_BIT_31); + bigOffset = NB.decodeInt64(largeOffsets, bigOffsetPos * 8); + } + result.setValues(packId, bigOffset); + return; + } + result.setValues(packId, offset); + } + + long getMemorySize() { + return (long) byteArrayLengh(offsets) + + byteArrayLengh(largeOffsets); + } + } + + /** + * Combines the fanout and oid list chunks, to lookup Oids with an efficient + * binary search + */ + private static class OidLookup { + + private static final int FANOUT = 256; + + private final int hashLength; + + private final int[] fanoutTable; + + private final byte[] oidLookup; + + /** + * Initialize the MultiPackIndexIndex. + * + * @param hashLength + * length of object hash. + * @param oidFanout + * content of OID Fanout Chunk. + * @param oidLookup + * content of OID Lookup Chunk. + * @throws MultiPackIndexFormatException + * MultiPackIndex file's format is different from we + * expected. + */ + OidLookup(int hashLength, @NonNull byte[] oidFanout, + @NonNull byte[] oidLookup) + throws MultiPackIndexFormatException { + this.hashLength = hashLength; + this.oidLookup = oidLookup; + + int[] table = new int[FANOUT]; + long uint32; + for (int k = 0; k < table.length; k++) { + uint32 = NB.decodeUInt32(oidFanout, k * 4); + if (uint32 > Integer.MAX_VALUE) { + throw new MultiPackIndexFormatException( + JGitText.get().multiPackIndexFileIsTooLargeForJgit); + } + table[k] = (int) uint32; + } + this.fanoutTable = table; + } + + /** + * Find the position in the MultiPackIndex file of the specified id. + * + * @param id + * the id for which the multi-pack-index position will be + * found. + * @return the MultiPackIndex position or -1 if the object was not + * found. + */ + int findMultiPackIndexPosition(AnyObjectId id) { + int levelOne = id.getFirstByte(); + int high = fanoutTable[levelOne]; + int low = 0; + if (levelOne > 0) { + low = fanoutTable[levelOne - 1]; + } + while (low < high) { + int mid = (low + high) >>> 1; + int cmp = id.compareTo(oidLookup, hashLength * mid); + if (cmp < 0) { + high = mid; + } else if (cmp == 0) { + return mid; + } else { + low = mid + 1; + } + } + return -1; + } + + void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, + int matchLimit) { + if (matches.size() >= matchLimit) { + return; + } + + if (oidLookup.length == 0) { + return; + } + + int high = fanoutTable[id.getFirstByte()]; + int low = id.getFirstByte() == 0 ? 0 + : fanoutTable[id.getFirstByte() - 1]; + do { + int p = (low + high) >>> 1; + int cmp = id.prefixCompare(oidLookup, idOffset(p)); + if (cmp < 0) { + high = p; + continue; + } + + if (cmp > 0) { + low = p + 1; + continue; + } + + // Got a match. + // We may have landed in the middle of the matches. Move + // backwards to the start of matches, then walk forwards. + while (0 < p + && id.prefixCompare(oidLookup, idOffset(p - 1)) == 0) { + p--; + } + while (p < high && id.prefixCompare(oidLookup, idOffset(p)) == 0 + && matches.size() < matchLimit) { + matches.add(ObjectId.fromRaw(oidLookup, idOffset(p))); + p++; + } + return; + } while (low < high); + } + + private int idOffset(int position) { + return position * hashLength; + } + + long getMemorySize() { + return 4L + byteArrayLengh(oidLookup) + (FANOUT * 4); + } + } +} 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 0000000000..b42c821a44 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java @@ -0,0 +1,428 @@ +/* + * 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.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. + * @return bytes written into the stream + * @throws IOException + * Error writing to the stream + */ + public long 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()))); + } + return expectedSize; + } 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 == null) { + 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 0000000000..f23665849e --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java @@ -0,0 +1,337 @@ +/* + * 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.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/PackExt.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java index e6daaeaca9..d5bb5f2e2f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java @@ -36,7 +36,10 @@ public enum PackExt { COMMIT_GRAPH("graph"), //$NON-NLS-1$ /** An object size index. */ - OBJECT_SIZE_INDEX("objsize"); //$NON-NLS-1$ + OBJECT_SIZE_INDEX("objsize"), //$NON-NLS-1$ + + /** Multi pack index */ + MULTI_PACK_INDEX("midx"); //$NON-NLS-1$ private final String ext; 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 dabc1f0c5f..bf87c4c9d6 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.internal.storage.file.PackBitmapIndex.FLAG_REUSE; 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.errors.MissingObjectException; 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 d07713db8e..e9ff02700d 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 static org.eclipse.jgit.lib.Ref.Storage.PACKED; 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 @@ class BlockReader { 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/storage/reftable/BlockWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java index c70f2e4914..0ddfa5798a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/BlockWriter.java @@ -524,8 +524,8 @@ class BlockWriter { this.oldId = oldId; this.newId = newId; - this.timeSecs = who.getWhen().getTime() / 1000L; - this.tz = (short) who.getTimeZoneOffset(); + this.timeSecs = who.getWhenAsInstant().getEpochSecond(); + this.tz = (short) (who.getZoneOffset().getTotalSeconds() / 60); this.name = who.getName().getBytes(UTF_8); this.email = who.getEmailAddress().getBytes(UTF_8); this.msg = message.getBytes(UTF_8); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java index 3c4bc75792..7e5f4ebbd4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java @@ -12,6 +12,7 @@ package org.eclipse.jgit.internal.storage.reftable; import java.io.IOException; import java.io.OutputStream; +import java.time.Instant; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; @@ -28,20 +29,26 @@ import org.eclipse.jgit.lib.ReflogEntry; * to shadow any lower reftable that may have the reference present. * <p> * By default all log entries within the range defined by - * {@link #setReflogExpireMinUpdateIndex(long)} and {@link #setReflogExpireMaxUpdateIndex(long)} are - * copied, even if no references in the output file match the log records. - * Callers may truncate the log to a more recent time horizon with - * {@link #setReflogExpireOldestReflogTimeMillis(long)}, or disable the log altogether with - * {@code setOldestReflogTimeMillis(Long.MAX_VALUE)}. + * {@link #setReflogExpireMinUpdateIndex(long)} and + * {@link #setReflogExpireMaxUpdateIndex(long)} are copied, even if no + * references in the output file match the log records. Callers may truncate the + * log to a more recent time horizon with + * {@link #setReflogExpireOlderThan(Instant)}, or disable the log + * altogether with {@code setReflogExpireOldestReflogTime(Instant.MAX)}. */ public class ReftableCompactor { private final ReftableWriter writer; + private final ArrayDeque<ReftableReader> tables = new ArrayDeque<>(); private boolean includeDeletes; + private long reflogExpireMinUpdateIndex = 0; + private long reflogExpireMaxUpdateIndex = Long.MAX_VALUE; - private long reflogExpireOldestReflogTimeMillis; + + private Instant reflogExpireOldestReflogTime = Instant.EPOCH; + private Stats stats; /** @@ -122,9 +129,29 @@ public class ReftableCompactor { * entries that predate {@code timeMillis} will be discarded. * Specified in Java standard milliseconds since the epoch. * @return {@code this} + * + * @deprecated Use {@link #setReflogExpireOlderThan(Instant)} instead + */ + @Deprecated(since="7.3") + public ReftableCompactor setReflogExpireOldestReflogTimeMillis( + long timeMillis) { + return setReflogExpireOlderThan(timeMillis == Long.MAX_VALUE + ? Instant.MAX + : Instant.ofEpochMilli(timeMillis)); + } + + /** + * Set oldest reflog time to preserve. + * + * @param cutTime + * oldest log time to preserve. Entries whose timestamps are + * {@code >= cutTime} will be copied into the output file. Log + * entries that predate {@code cutTime} will be discarded. + * @return {@code this} */ - public ReftableCompactor setReflogExpireOldestReflogTimeMillis(long timeMillis) { - reflogExpireOldestReflogTimeMillis = timeMillis; + public ReftableCompactor setReflogExpireOlderThan( + Instant cutTime) { + reflogExpireOldestReflogTime = cutTime; return this; } @@ -182,14 +209,15 @@ public class ReftableCompactor { } private void mergeLogs(MergedReftable mr) throws IOException { - if (reflogExpireOldestReflogTimeMillis == Long.MAX_VALUE) { + if (reflogExpireOldestReflogTime == Instant.MAX) { return; } try (LogCursor lc = mr.allLogs()) { while (lc.next()) { long updateIndex = lc.getUpdateIndex(); - if (updateIndex > reflogExpireMaxUpdateIndex || updateIndex < reflogExpireMinUpdateIndex) { + if (updateIndex > reflogExpireMaxUpdateIndex + || updateIndex < reflogExpireMinUpdateIndex) { continue; } @@ -203,14 +231,9 @@ public class ReftableCompactor { } PersonIdent who = log.getWho(); - if (who.getWhen().getTime() >= reflogExpireOldestReflogTimeMillis) { - writer.writeLog( - refName, - updateIndex, - who, - log.getOldId(), - log.getNewId(), - log.getComment()); + if (who.getWhenAsInstant().compareTo(reflogExpireOldestReflogTime) >= 0) { + writer.writeLog(refName, updateIndex, who, log.getOldId(), + log.getNewId(), log.getComment()); } } } 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 e15c7af932..7921052aaa 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 class BranchConfig { * @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/CommitConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java index f701a41d67..b1ba5dfa28 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 @@ public class CommitConfig { 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 07c5fa4500..345cb22f80 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.AtomicBoolean; 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 @@ public class Config { * 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 class Config { * * @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 class Config { * 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 class Config { */ 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 class Config { */ 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 class Config { * @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 class Config { * @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 class Config { * @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 class Config { * @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 class Config { * 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 class Config { * @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 class Config { * 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 class Config { */ 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 class Config { * @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 a57f1b714a..c4550329d3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -446,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"; @@ -593,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 @@ -1016,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 @@ -1063,4 +1101,18 @@ public final class ConfigConstants { * @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 997f4ed314..9de8392690 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -345,6 +345,15 @@ public final class Constants { public static final String XDG_CONFIG_HOME = "XDG_CONFIG_HOME"; /** + * The key of the XDG_CACHE_HOME directory defined in the + * <a href="https://wiki.archlinux.org/index.php/XDG_Base_Directory"> + * XDG Base Directory specification</a>. + * + * @since 7.3 + */ + public static final String XDG_CACHE_HOME = "XDG_CACHE_HOME"; + + /** * The environment variable that limits how close to the root of the file * systems JGit will traverse when looking for a repository root. */ 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 49602a75eb..0e27b2743c 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 @@ package org.eclipse.jgit.lib; 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 class CoreConfig { * 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 class CoreConfig { /** 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,17 +157,44 @@ public class CoreConfig { * 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; @@ -169,6 +205,18 @@ public class CoreConfig { 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 * @@ -198,7 +246,13 @@ public class CoreConfig { 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, @@ -210,6 +264,68 @@ public class CoreConfig { 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; } /** @@ -260,4 +376,70 @@ public class CoreConfig { 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 a71549c92e..3059f283fe 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.Matcher; 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 @@ import org.eclipse.jgit.util.StringUtils; */ 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 class DefaultTypedConfigGetter implements TypedConfigGetter { @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 class DefaultTypedConfigGetter implements TypedConfigGetter { @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 class DefaultTypedConfigGetter implements TypedConfigGetter { @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 class DefaultTypedConfigGetter implements TypedConfigGetter { } 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 class DefaultTypedConfigGetter implements TypedConfigGetter { } 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 76ed36a6e5..23d16db39f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java @@ -74,8 +74,7 @@ public class GpgConfig { * 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); 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 f22642c4ce..50f4a83b93 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java @@ -45,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$ 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 09cb5a83dd..49d5224325 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java @@ -356,6 +356,40 @@ public abstract class RefDatabase { } /** + * 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 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 0562840915..c9dc6da4ba 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.IOException; 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.Collections; 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; @@ -132,6 +136,8 @@ public abstract class Repository implements AutoCloseable { private final String initialBranch; + private final AtomicReference<Boolean> caseInsensitiveWorktree = new AtomicReference<>(); + /** * Initialize a new repository instance. * @@ -1577,6 +1583,40 @@ public abstract class Repository implements AutoCloseable { } /** + * 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. * @@ -1692,10 +1732,13 @@ public abstract class Repository implements AutoCloseable { * @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 @@ -1703,15 +1746,17 @@ public abstract class Repository implements AutoCloseable { * * @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/TypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TypedConfigGetter.java index 0c03adcab8..3d4e0d1f3c 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.List; 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 @@ public interface TypedConfigGetter { * 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 @@ public interface TypedConfigGetter { * @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 @@ public interface TypedConfigGetter { * @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 @@ public interface TypedConfigGetter { * @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 @@ public interface TypedConfigGetter { * 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 @@ public interface TypedConfigGetter { * @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/revplot/PlotWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java index 0f6bd2d6cc..c8c454a228 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java @@ -169,8 +169,9 @@ public class PlotWalk extends RevWalk { } long timeof(RevObject o) { - if (o instanceof RevCommit) - return ((RevCommit) o).getCommitTime(); + if (o instanceof RevCommit) { + return ((RevCommit) o).getCommitTime() * 1000L; + } if (o instanceof RevTag) { RevTag tag = (RevTag) o; try { @@ -179,7 +180,7 @@ public class PlotWalk extends RevWalk { return 0; } PersonIdent who = tag.getTaggerIdent(); - return who != null ? who.getWhen().getTime() : 0; + return who != null ? who.getWhenAsInstant().toEpochMilli() : 0; } return 0; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java index 35ef51f4fd..12e6c4ea98 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FollowFilter.java @@ -18,7 +18,7 @@ import org.eclipse.jgit.diff.DiffConfig; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.treewalk.TreeWalk; -import org.eclipse.jgit.treewalk.filter.PathFilter; +import org.eclipse.jgit.treewalk.filter.ChangedPathTreeFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; /** @@ -56,39 +56,44 @@ public class FollowFilter extends TreeFilter { * @since 3.0 */ public static FollowFilter create(String path, DiffConfig cfg) { - return new FollowFilter(PathFilter.create(path), cfg); + return new FollowFilter(ChangedPathTreeFilter.create(path), cfg); } - private final PathFilter path; + private final ChangedPathTreeFilter path; final DiffConfig cfg; private RenameCallback renameCallback; - FollowFilter(PathFilter path, DiffConfig cfg) { + FollowFilter(ChangedPathTreeFilter path, DiffConfig cfg) { this.path = path; this.cfg = cfg; } - /** @return the path this filter matches. */ /** * Get the path this filter matches. * * @return the path this filter matches. */ public String getPath() { - return path.getPath(); + return path.getPaths().get(0); } @Override public boolean include(TreeWalk walker) throws MissingObjectException, IncorrectObjectTypeException, IOException { - return path.include(walker) && ANY_DIFF.include(walker); + return path.include(walker); + } + + @Override + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + MutableBoolean cpfUsed) { + return path.shouldTreeWalk(c, rw, cpfUsed); } @Override public boolean shouldBeRecursive() { - return path.shouldBeRecursive() || ANY_DIFF.shouldBeRecursive(); + return path.shouldBeRecursive(); } @Override @@ -105,9 +110,7 @@ public class FollowFilter extends TreeFilter { @SuppressWarnings("nls") @Override public String toString() { - return "(FOLLOW(" + path.toString() + ")" // - + " AND " // - + ANY_DIFF.toString() + ")"; + return "(FOLLOW(" + path.toString() + "))"; } /** 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 55ddebf288..871545fca2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java @@ -401,13 +401,13 @@ public class RevCommit extends RevObject { * @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); } 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 9f0e28d0ce..41f98bad84 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.text.MessageFormat; 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; @@ -523,6 +528,27 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable { } /** + * 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>. * @@ -545,7 +571,26 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable { 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; @@ -561,16 +606,11 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable { 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; @@ -582,7 +622,7 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable { } 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/TreeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java index 99943b78e6..e9a3e72c7f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java @@ -12,15 +12,11 @@ package org.eclipse.jgit.revwalk; import java.io.IOException; import java.util.List; -import java.util.Optional; -import java.util.Set; -import org.eclipse.jgit.internal.storage.commitgraph.ChangedPathFilter; import org.eclipse.jgit.diff.DiffConfig; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.RenameDetector; -import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.StopWalkException; @@ -28,6 +24,7 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.treewalk.filter.TreeFilter.MutableBoolean; /** * Filter applying a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} against @@ -50,6 +47,8 @@ public class TreeRevFilter extends RevFilter { private final TreeWalk pathFilter; + private final MutableBoolean changedPathFilterUsed = new MutableBoolean(); + private long changedPathFilterTruePositive = 0; private long changedPathFilterFalsePositive = 0; @@ -126,24 +125,15 @@ public class TreeRevFilter extends RevFilter { } trees[nParents] = c.getTree(); tw.reset(trees); + changedPathFilterUsed.reset(); if (nParents == 1) { // We have exactly one parent. This is a very common case. // int chgs = 0, adds = 0; - boolean changedPathFilterUsed = false; - boolean mustCalculateChgs = true; - ChangedPathFilter cpf = c.getChangedPathFilter(walker); - if (cpf != null) { - Optional<Set<byte[]>> paths = pathFilter.getFilter() - .getPathsBestEffort(); - if (paths.isPresent()) { - changedPathFilterUsed = true; - if (paths.get().stream().noneMatch(cpf::maybeContains)) { - mustCalculateChgs = false; - } - } - } + TreeFilter tf = pathFilter.getFilter(); + boolean mustCalculateChgs = tf.shouldTreeWalk(c, walker, + changedPathFilterUsed); if (mustCalculateChgs) { while (tw.next()) { chgs++; @@ -153,7 +143,7 @@ public class TreeRevFilter extends RevFilter { break; // no point in looking at this further. } } - if (changedPathFilterUsed) { + if (changedPathFilterUsed.get()) { if (chgs > 0) { changedPathFilterTruePositive++; } else { @@ -161,7 +151,7 @@ public class TreeRevFilter extends RevFilter { } } } else { - if (changedPathFilterUsed) { + if (changedPathFilterUsed.get()) { changedPathFilterNegative++; } } @@ -315,9 +305,7 @@ public class TreeRevFilter extends RevFilter { } private void updateFollowFilter(ObjectId[] trees, DiffConfig cfg, - RevCommit commit) - throws MissingObjectException, IncorrectObjectTypeException, - CorruptObjectException, IOException { + RevCommit commit) throws IOException { TreeWalk tw = pathFilter; FollowFilter oldFilter = (FollowFilter) tw.getFilter(); tw.setFilter(TreeFilter.ANY_DIFF); 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 becc8082ba..105cba7d28 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 class SubmoduleWalk implements AutoCloseable { 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 aaf9f8a08a..9d9f5495fe 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java @@ -760,6 +760,15 @@ public class AmazonS3 { SAXParserFactory saxParserFactory = SAXParserFactory .newInstance(); saxParserFactory.setNamespaceAware(true); + saxParserFactory.setFeature( + "http://xml.org/sax/features/external-general-entities", //$NON-NLS-1$ + false); + saxParserFactory.setFeature( + "http://xml.org/sax/features/external-parameter-entities", //$NON-NLS-1$ + false); + saxParserFactory.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", //$NON-NLS-1$ + true); xr = saxParserFactory.newSAXParser().getXMLReader(); } catch (SAXException | ParserConfigurationException e) { throw new IOException( 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 73eddb8e21..f10b7bf452 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 @@ public class HttpConfig { 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 @@ public class HttpConfig { 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/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java index 4de6ff825f..7b5842b712 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/treewalk/filter/AndTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java index c6804da039..b35dbebd17 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/AndTreeFilter.java @@ -12,11 +12,14 @@ package org.eclipse.jgit.treewalk.filter; import java.io.IOException; +import java.util.Arrays; import java.util.Collection; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; /** @@ -100,6 +103,13 @@ public abstract class AndTreeFilter extends TreeFilter { } @Override + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + MutableBoolean cpfUsed) { + return a.shouldTreeWalk(c, rw, cpfUsed) + && b.shouldTreeWalk(c, rw, cpfUsed); + } + + @Override public int matchFilter(TreeWalk walker) throws MissingObjectException, IncorrectObjectTypeException, IOException { @@ -174,6 +184,13 @@ public abstract class AndTreeFilter extends TreeFilter { } @Override + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + MutableBoolean cpfUsed) { + return Arrays.stream(subfilters) + .allMatch(t -> t.shouldTreeWalk(c, rw, cpfUsed)); + } + + @Override public TreeFilter clone() { final TreeFilter[] s = new TreeFilter[subfilters.length]; for (int i = 0; i < s.length; i++) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ChangedPathTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ChangedPathTreeFilter.java new file mode 100644 index 0000000000..a74b9b617f --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ChangedPathTreeFilter.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2025, 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 + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.treewalk.filter; + +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.commitgraph.ChangedPathFilter; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.util.StringUtils; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Filter tree entries that modified the contents of particular file paths. + * <p> + * Equivalent to AndTreeFilter(PathFilter, AnyDiffFilter). This filter uses + * {@link org.eclipse.jgit.internal.storage.commitgraph.ChangedPathFilter} + * (bloom filters) when available to discard commits without diffing their + * trees. + * + * @since 7.3 + */ +public class ChangedPathTreeFilter extends TreeFilter { + + private TreeFilter pathFilter; + + private List<String> paths; + + private List<byte[]> rawPaths; + + /** + * Create a TreeFilter for trees modifying one or more user supplied paths. + * <p> + * Path strings are relative to the root of the repository. If the user's + * input should be assumed relative to a subdirectory of the repository the + * caller must prepend the subdirectory's path prior to creating the filter. + * <p> + * Path strings use '/' to delimit directories on all platforms. + * <p> + * Paths may appear in any order within the collection. Sorting may be done + * internally when the group is constructed if doing so will improve path + * matching performance. + * + * @param paths + * the paths to test against. Must have at least one entry. + * @return a new filter for the list of paths supplied. + */ + public static ChangedPathTreeFilter create(String... paths) { + return new ChangedPathTreeFilter(paths); + } + + private ChangedPathTreeFilter(String... paths) { + List<String> filtered = Arrays.stream(paths) + .map(s -> StringUtils.trim(s, '/')) + .collect(Collectors.toList()); + + if (filtered.size() == 0) + throw new IllegalArgumentException( + JGitText.get().atLeastOnePathIsRequired); + + if (filtered.stream().anyMatch(s -> s.isEmpty() || s.isBlank())) { + throw new IllegalArgumentException( + JGitText.get().emptyPathNotPermitted); + } + + this.paths = filtered; + this.rawPaths = this.paths.stream().map(Constants::encode) + .collect(Collectors.toList()); + if (filtered.size() == 1) { + this.pathFilter = PathFilter.create(paths[0]); + } else { + this.pathFilter = OrTreeFilter.create(Arrays.stream(paths) + .map(PathFilter::create).collect(Collectors.toList())); + } + } + + @Override + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + MutableBoolean cpfUsed) { + ChangedPathFilter cpf = c.getChangedPathFilter(rw); + if (cpf == null) { + return true; + } + if (cpfUsed != null) { + cpfUsed.orValue(true); + } + // return true if at least one path might exist in cpf + return rawPaths.stream().anyMatch(cpf::maybeContains); + } + + @Override + public boolean include(TreeWalk walker) throws IOException { + return pathFilter.include(walker) && ANY_DIFF.include(walker); + } + + @Override + public boolean shouldBeRecursive() { + return pathFilter.shouldBeRecursive() || ANY_DIFF.shouldBeRecursive(); + } + + @Override + public ChangedPathTreeFilter clone() { + return this; + } + + /** + * Get the paths this filter matches. + * + * @return the paths this filter matches. + */ + public List<String> getPaths() { + return paths; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + return "(CHANGED_PATH(" + pathFilter.toString() + ")" // + + " AND " // + + ANY_DIFF.toString() + ")"; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java index 3c18a9f98d..ce2382552b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/OrTreeFilter.java @@ -12,11 +12,14 @@ package org.eclipse.jgit.treewalk.filter; import java.io.IOException; +import java.util.Arrays; import java.util.Collection; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; /** @@ -116,6 +119,13 @@ public abstract class OrTreeFilter extends TreeFilter { } @Override + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + MutableBoolean cpfUsed) { + return a.shouldTreeWalk(c, rw, cpfUsed) + || b.shouldTreeWalk(c, rw, cpfUsed); + } + + @Override public boolean shouldBeRecursive() { return a.shouldBeRecursive() || b.shouldBeRecursive(); } @@ -164,6 +174,13 @@ public abstract class OrTreeFilter extends TreeFilter { } @Override + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + MutableBoolean cpfUsed) { + return Arrays.stream(subfilters) + .anyMatch(t -> t.shouldTreeWalk(c, rw, cpfUsed)); + } + + @Override public boolean shouldBeRecursive() { for (TreeFilter f : subfilters) if (f.shouldBeRecursive()) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java index a9066dc8f8..8159843312 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilter.java @@ -14,9 +14,12 @@ import java.io.IOException; import java.util.Optional; import java.util.Set; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; @@ -210,14 +213,38 @@ public abstract class TreeFilter { public abstract boolean shouldBeRecursive(); /** - * If this filter checks that at least one of the paths in a set has been + * Return true if the tree entries within this commit require + * {@link #include(TreeWalk)} to correctly determine whether they are + * interesting to report. + * <p> + * Otherwise, all tree entries within this commit are UNINTERESTING for this + * tree filter. + * + * @param c + * the commit being considered by the TreeFilter. + * @param rw + * the RevWalk used in retrieving relevant commit data. + * @param cpfUsed + * if not null, it reports if the changedPathFilter was used in + * this method + * @return True if the tree entries within c require + * {@link #include(TreeWalk)}. + * @since 7.3 + */ + public boolean shouldTreeWalk(RevCommit c, RevWalk rw, + @Nullable MutableBoolean cpfUsed) { + return true; + } + + /** + * If this filter checks that a specific set of paths have all been * modified, returns that set of paths to be checked against a changed path * filter. Otherwise, returns empty. * * @return a set of paths, or empty - * - * @since 6.7 + * @deprecated use {@code shouldTreeWalk} instead. */ + @Deprecated(since = "7.3") public Optional<Set<byte[]>> getPathsBestEffort() { return Optional.empty(); } @@ -242,4 +269,33 @@ public abstract class TreeFilter { } return n.replace('$', '.'); } + + /** + * Mutable wrapper to return a boolean in a function parameter. + * + * @since 7.3 + */ + public static class MutableBoolean { + private boolean value; + + /** + * Return the boolean value. + * + * @return The state of the internal boolean value. + */ + public boolean get() { + return value; + } + + void orValue(boolean v) { + value = value || v; + } + + /** + * Reset the boolean value. + */ + public void reset() { + value = false; + } + } } 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 12af374b2e..c8421d6012 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 class ChangeIdUtil { } } - 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 class ChangeIdUtil { 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 59bbacfa76..6a40fad1db 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -363,6 +363,7 @@ public abstract class FS { private static FileStoreAttributes getFileStoreAttributes(Path dir) { FileStore s; + CompletableFuture<Optional<FileStoreAttributes>> f = null; try { if (Files.exists(dir)) { s = Files.getFileStore(dir); @@ -385,7 +386,7 @@ public abstract class FS { return FALLBACK_FILESTORE_ATTRIBUTES; } - CompletableFuture<Optional<FileStoreAttributes>> f = CompletableFuture + f = CompletableFuture .supplyAsync(() -> { Lock lock = locks.computeIfAbsent(s, l -> new ReentrantLock()); @@ -455,10 +456,13 @@ public abstract class FS { } // fall through and return fallback } catch (IOException | ExecutionException | CancellationException e) { + cancel(f); LOG.error(e.getMessage(), e); } catch (TimeoutException | SecurityException e) { + cancel(f); // use fallback } catch (InterruptedException e) { + cancel(f); LOG.error(e.getMessage(), e); Thread.currentThread().interrupt(); } @@ -467,6 +471,13 @@ public abstract class FS { return FALLBACK_FILESTORE_ATTRIBUTES; } + private static void cancel( + CompletableFuture<Optional<FileStoreAttributes>> f) { + if (f != null) { + f.cancel(true); + } + } + @SuppressWarnings("boxing") private static Duration measureMinimalRacyInterval(Path dir) { LOG.debug("{}: start measure minimal racy interval in {}", //$NON-NLS-1$ 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 524126b098..332e65985e 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 @@ import org.eclipse.jgit.lib.PersonIdent; */ public class GitDateFormatter { - private DateFormat dateTimeInstance; + private DateTimeFormatter dateTimeFormat; - private DateFormat dateTimeInstance2; + private DateTimeFormatter dateTimeFormat2; private final Format format; @@ -96,30 +96,34 @@ public class GitDateFormatter { 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 class GitDateFormatter { @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.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/GitTimeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java index 7d00fcd5ed..acaa1ce563 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitTimeParser.java @@ -11,6 +11,7 @@ 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; @@ -97,6 +98,40 @@ public class GitTimeParser { 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 { 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 820ac2db91..e3e3e04fd9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SignatureUtils.java @@ -48,7 +48,7 @@ public final class SignatureUtils { if (verification.creationDate() != null) { // Use the creator's timezone for the signature date PersonIdent dateId = new PersonIdent(creator, - verification.creationDate()); + verification.creationDate().toInstant()); result.append( MessageFormat.format(JGitText.get().verifySignatureMade, formatter.formatDate(dateId))); 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 2fbd12dcc5..e381a3bcc9 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 final class StringUtils { } /** + * 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 55cc878e02..0b7c6204f2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -492,6 +492,36 @@ public abstract class SystemReader { } /** + * Gets the directory denoted by environment variable XDG_CACHE_HOME. If + * the variable is not set or empty, return a path for + * {@code $HOME/.cache}. + * + * @param fileSystem + * {@link FS} to get the user's home directory + * @return a {@link Path} denoting the directory, which may exist or not, or + * {@code null} if the environment variable is not set and there is + * no home directory, or the path is invalid. + * @since 7.3 + */ + public Path getXdgCacheDirectory(FS fileSystem) { + String cacheHomePath = getenv(Constants.XDG_CACHE_HOME); + if (StringUtils.isEmptyOrNull(cacheHomePath)) { + File home = fileSystem.userHome(); + if (home == null) { + return null; + } + cacheHomePath = new File(home, ".cache").getAbsolutePath(); //$NON-NLS-1$ + } + try { + return Paths.get(cacheHomePath); + } catch (InvalidPathException e) { + LOG.error(JGitText.get().logXDGCacheHomeInvalid, cacheHomePath, + e); + } + return null; + } + + /** * Update config and its parents if they seem modified * * @param config @@ -523,7 +553,7 @@ public abstract class SystemReader { * * @deprecated Use {@link #now()} */ - @Deprecated + @Deprecated(since = "7.1") public abstract long getCurrentTime(); /** @@ -569,7 +599,7 @@ public abstract class SystemReader { * * @deprecated Use {@link #getTimeZoneAt(Instant)} instead. */ - @Deprecated + @Deprecated(since = "7.1") public abstract int getTimezone(long when); /** @@ -592,7 +622,7 @@ public abstract class SystemReader { * * @deprecated Use {@link #getTimeZoneId()} */ - @Deprecated + @Deprecated(since = "7.1") public TimeZone getTimeZone() { return TimeZone.getDefault(); } @@ -18,7 +18,7 @@ <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> <packaging>pom</packaging> - <version>7.2.0-SNAPSHOT</version> + <version>7.4.0-SNAPSHOT</version> <name>JGit - Parent</name> <url>${jgit-url}</url> @@ -33,7 +33,7 @@ </description> <scm> - <url>https://eclipse.gerrithub.io/plugins/gitiles/eclipse-jgit/jgit</url> + <url>https://eclipse.gerrithub.io/admin/repos/eclipse-jgit/jgit</url> <connection>scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit</connection> </scm> @@ -118,9 +118,9 @@ <project.build.outputTimestamp>${commit.time.iso}</project.build.outputTimestamp> - <jgit-last-release-version>7.1.0.202411261347-r</jgit-last-release-version> + <jgit-last-release-version>7.3.0.202506031305-r</jgit-last-release-version> <ant-version>1.10.15</ant-version> - <apache-sshd-version>2.14.0</apache-sshd-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> @@ -130,25 +130,25 @@ <commons-compress-version>1.27.1</commons-compress-version> <osgi-core-version>6.0.0</osgi-core-version> <servlet-api-version>6.1.0</servlet-api-version> - <jetty-version>12.0.16</jetty-version> - <japicmp-version>0.23.0</japicmp-version> + <jetty-version>12.0.22</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.11.2</maven-javadoc-plugin-version> - <gson-version>2.11.0</gson-version> - <bouncycastle-version>1.79</bouncycastle-version> - <spotbugs-maven-plugin-version>4.8.6.6</spotbugs-maven-plugin-version> - <maven-project-info-reports-plugin-version>3.8.0</maven-project-info-reports-plugin-version> + <gson-version>2.13.1</gson-version> + <bouncycastle-version>1.81</bouncycastle-version> + <spotbugs-maven-plugin-version>4.9.3.0</spotbugs-maven-plugin-version> + <maven-project-info-reports-plugin-version>3.9.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-plugin-version>3.5.3</maven-surefire-plugin-version> <maven-surefire-report-plugin-version>${maven-surefire-plugin-version}</maven-surefire-report-plugin-version> - <maven-compiler-plugin-version>3.13.0</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.27.0</assertj-version> - <jna-version>5.15.0</jna-version> - <byte-buddy-version>1.15.11</byte-buddy-version> + <assertj-version>3.27.3</assertj-version> + <jna-version>5.17.0</jna-version> + <byte-buddy-version>1.17.5</byte-buddy-version> <!-- Properties to enable jacoco code coverage analysis --> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> @@ -208,7 +208,7 @@ <plugin> <artifactId>maven-clean-plugin</artifactId> - <version>3.4.0</version> + <version>3.4.1</version> </plugin> <plugin> @@ -305,7 +305,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.8.12</version> + <version>0.8.13</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -337,12 +337,12 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> - <version>3.1.3</version> + <version>3.1.4</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> - <version>3.1.3</version> + <version>3.1.4</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>3.4.1</version> + <version>3.5.0</version> </plugin> <plugin> <groupId>org.eclipse.dash</groupId> @@ -372,7 +372,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-artifact-plugin</artifactId> - <version>3.5.3</version> + <version>3.6.0</version> <configuration> <ignore>**/*cyclonedx.json</ignore> <reproducible>true</reproducible> @@ -623,7 +623,7 @@ <plugin> <groupId>io.github.git-commit-id</groupId> <artifactId>git-commit-id-maven-plugin</artifactId> - <version>9.0.1</version> + <version>9.0.2</version> <executions> <execution> <id>get-the-git-infos</id> @@ -642,7 +642,7 @@ <plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> - <version>4.0.1</version> + <version>4.2.0</version> <dependencies> <dependency> <groupId>org.apache.groovy</groupId> @@ -886,7 +886,7 @@ <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> - <version>1.17.1</version> + <version>1.18.0</version> </dependency> <dependency> @@ -898,13 +898,13 @@ <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> - <version>2.18.0</version> + <version>2.19.0</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> - <version>1.3.4</version> + <version>1.3.5</version> </dependency> <dependency> @@ -1007,7 +1007,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.2</version> + <version>5.18.0</version> </dependency> <dependency> @@ -1116,7 +1116,7 @@ <dependency> <groupId>org.eclipse.jdt</groupId> <artifactId>ecj</artifactId> - <version>3.38.0</version> + <version>3.40.0</version> </dependency> </dependencies> </plugin> diff --git a/tools/BUILD b/tools/BUILD index 844f0049e6..379a9bd34c 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -54,7 +54,7 @@ errorprone_checks = [ "-Xep:ArrayHashCode:ERROR", "-Xep:ArraysAsListPrimitiveArray:ERROR", "-Xep:ArrayToString:ERROR", - "-Xep:AssertEqualsArgumentOrderChecker:ERROR", + "-Xep:AssertEqualsArgumentOrderChecker:WARN", "-Xep:AssertionFailureIgnored:WARN", "-Xep:AsyncCallableReturnsNull:ERROR", "-Xep:AsyncFunctionReturnsNull:ERROR", diff --git a/tools/bazlets.bzl b/tools/bazlets.bzl deleted file mode 100644 index f089af473a..0000000000 --- a/tools/bazlets.bzl +++ /dev/null @@ -1,18 +0,0 @@ -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") - -NAME = "com_googlesource_gerrit_bazlets" - -def load_bazlets( - commit, - local_path = None): - if not local_path: - git_repository( - name = NAME, - remote = "https://gerrit.googlesource.com/bazlets", - commit = commit, - ) - else: - native.local_repository( - name = NAME, - path = local_path, - ) |