diff --git a/.bazelrc b/.bazelrc index 385a71d7cb0..2142af857fe 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,7 +1,4 @@ -# TODO(davido): Migrate all dependencies from WORKSPACE to MODULE.bazel -# https://issues.gerritcodereview.com/issues/303819949 -common --enable_bzlmod --lockfile_mode=error -common --enable_workspace +common --lockfile_mode=error build --workspace_status_command="python3 ./tools/workspace_status.py" build --repository_cache=~/.gerritcodereview/bazel-cache/repository diff --git a/.bazelversion b/.bazelversion index e8be68404bc..37ad5c8b19d 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.6.1 +9.0.1 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..ec4bb386bcf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2fd172793fc..1bf6b52e82d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ target/ infer-out bazel-* +CLAUDE.md # Do not add editor- and OS-specific files like *~ (Emacs) and .DS_Store # (macOS). Instead, add them to $XDG_CONFIG_HOME/git/ignore diff --git a/BUILD b/BUILD index b8d8b9f0b79..b9be9cb2820 100644 --- a/BUILD +++ b/BUILD @@ -10,8 +10,10 @@ genrule( "//org.eclipse.jgit.archive:jgit-archive", "//org.eclipse.jgit.http.apache:http-apache", "//org.eclipse.jgit.http.server:jgit-servlet", + "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8", "//org.eclipse.jgit.lfs:jgit-lfs", "//org.eclipse.jgit.lfs.server:jgit-lfs-server", + "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8", "//org.eclipse.jgit.junit:junit", "//org.eclipse.jgit.ssh.apache:ssh-apache", "//org.eclipse.jgit.ssh.apache.agent:ssh-apache-agent", diff --git a/Documentation/config-options.md b/Documentation/config-options.md index 3d4811575a1..0ba67c78b0f 100644 --- a/Documentation/config-options.md +++ b/Documentation/config-options.md @@ -41,7 +41,7 @@ For details on native git options see also the official [git config documentatio | `core.fileMode` | Auto detects if file modes are supported | ✅ | Tells Git if the executable bit of files in the working tree is to be honored. | | `core.hideDotFiles` | `dotGitOnly` | ✅ | Windows only. If `true`, mark newly-created directories and files whose name starts with a dot as hidden. If `dotGitOnly`, only the `.git/` directory is hidden, but no other files starting with a dot. | | `core.hooksPath` | `$GIT_DIR/hooks` | ✅ | Path to look for hooks. | -| `core.logAllRefUpdates` | `true` in a repository with working tree, `false` in bare repository | ✅ | Enable the reflog. | +| `core.logAllRefUpdates` | `true` in a repository with working tree, `false` in bare repository | ✅ | Enable the reflog. `true` to log updates only for `refs/heads/**`, `refs/remotes/**`, `refs/notes/**`, and `HEAD`, `always` to log for all refs, `false` to disable reflog updates | | `core.packedGitLimit` | `10 MiB` | ✅ | Maximum number of bytes to cache in memory from pack files. | | `core.packedGitMmap` | `false` | ✅ | Whether to use Java NIO virtual memory mapping for JGit buffer cache. When set to `true` enables use of Java NIO virtual memory mapping for cache windows, `false` reads entire window into a `byte[]` with standard read calls. `true` is experimental and may cause instabilities and crashes since Java doesn't support explicit unmapping of file regions mapped to virtual memory. | | `core.packedGitOpenFiles` | `128` | ⃞ | Maximum number of streams to open at a time. Open packs count against the process limits. | @@ -66,9 +66,10 @@ For details on native git options see also the official [git config documentatio ## __fetch__ options -| option | default | git option | description | -|---------|---------|------------|-------------| +| option | default | git option | description | +|---------------------------|---------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| | `fetch.useNegotiationTip` | `false` | ✅ | When enabled it restricts the client negotiation on unrelated branches i.e. only send haves for the refs that the client is interested in fetching. | +| `fetch.autogc` | `true` | ⃞ | Perform an automatic garbage collection after the fetch operation has been completed. | ## __gc__ options @@ -82,7 +83,7 @@ For details on native git options see also the official [git config documentatio | `gc.logExpiry` | `1.day.ago` | ✅ | If the file `gc.log` exists, then auto gc will print its content and exit successfully instead of running unless that file is more than `gc.logExpiry` old. | | `gc.packRefs`| `true` | ✅ | This variable determines whether JGit garbage collection will also pack refs. This can be set to `notbare` to enable it within all non-bare repos or it can be set to a boolean value. | | `gc.pruneExpire` | `2.weeks.ago` | ✅ | Grace period after which unreachable objects will be pruned. | -| `gc.prunePackExpire` | `1.hour.ago` | ⃞ | Grace period after which packfiles only containing unreachable objects will be pruned. | +| `gc.prunePackExpire` | `1.hour.ago` | ⃞ | Grace period after which packfiles containing only unreachable objects will be pruned. | | `gc.writeChangedPaths` | `false`| ⃞ | Whether bloom filter should be written to commit-graph during a gc operation. | | `gc.writeCommitGraph`| `false` | ⃞ | If true, then gc will rewrite the commit-graph file when jgit gc is run. | @@ -137,6 +138,16 @@ 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. | + +## __receive__ options + +| option | default | git option | description | +|------------------|---------|------------|--------------------------------------------------------------------------------------------| +| `receive.autogc` | `true` | ✅ | Perform an automatic garbage collection after a receive-pack operation has been completed. | +| `receive.maxCommandBytes` | `3 MiB` | ⃞ | Maximum number of bytes to read from the receive-pack command block before the pack data. If set to `0`, there is no limit. | +| `receive.maxCommandDiscardBytes` | `-1` | ⃞ | Maximum number of command-block bytes to discard after `receive.maxCommandBytes` is exceeded, so JGit can report a side-band error before disconnecting. If set to `0`, there is no limit. If set to `-1`, JGit uses the larger of `3 * receive.maxCommandBytes` and `3 MiB`. | + + ## reftable options | option | default | git option | description | diff --git a/MODULE.bazel b/MODULE.bazel index 7b70fa27d66..061e5a2faa3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,7 +1,11 @@ module(name = "jgit") -bazel_dep(name = "rules_java", version = "8.11.0") +bazel_dep(name = "bazel_features", version = "1.42.1") +bazel_dep(name = "rules_android", version = "0.7.1") +bazel_dep(name = "rules_go", version = "0.60.0") +bazel_dep(name = "rules_java", version = "9.3.0") bazel_dep(name = "rules_jvm_external", version = "6.10") +bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "rbe_autoconfig") git_override( module_name = "rbe_autoconfig", @@ -17,38 +21,39 @@ git_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:git.bzl", "g git_repository( name = "com_googlesource_gerrit_bazlets", - commit = "f9c119e45d9a241bee720b7fbd6c7fdbc952da5f", + commit = "5ef765b723e81759359048edb43d314046178ac4", remote = "https://gerrit.googlesource.com/bazlets", ) -BOUNCYCASTLE_VERSION = "1.83" +BOUNCYCASTLE_VERSION = "1.85" -BYTE_BUDDY_VERSION = "1.18.4" +BYTE_BUDDY_VERSION = "1.18.11" -JETTY_VERSION = "12.1.5" +JETTY_VERSION = "12.1.11" JMH_VERSION = "1.37" -JNA_VERSION = "5.18.1" +JNA_VERSION = "5.19.1" -SLF4J_VERSION = "2.0.17" +SLF4J_VERSION = "2.0.18" -SSHD_VERSION = "2.17.1" +SSHD_VERSION = "2.19.0" maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( name = "external_deps", artifacts = [ "args4j:args4j:2.37", - "com.google.code.gson:gson:2.13.2", + "com.google.code.gson:gson:2.14.0", "com.google.errorprone:error_prone_type_annotations:2.46.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.20.0", - "commons-io:commons-io:2.21.0", - "commons-logging:commons-logging:1.3.5", + "commons-codec:commons-codec:1.22.1", + "commons-io:commons-io:2.22.0", + "commons-logging:commons-logging:1.4.0", "jakarta.servlet:jakarta.servlet-api:6.1.0", + "javax.servlet:javax.servlet-api:4.0.1", "junit:junit:4.13.2", "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, @@ -74,15 +79,19 @@ maven.install( "org.eclipse.jetty:jetty-session:" + JETTY_VERSION, "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VERSION, "org.eclipse.jetty:jetty-util:" + JETTY_VERSION, - "org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VERSION, + "org.eclipse.jetty.ee8:jetty-ee8-nested:" + JETTY_VERSION, + "org.eclipse.jetty.ee8:jetty-ee8-security:" + JETTY_VERSION, + "org.eclipse.jetty.ee8:jetty-ee8-servlet:" + JETTY_VERSION, + "org.eclipse.jetty.ee11:jetty-ee11-servlet:" + JETTY_VERSION, "org.hamcrest:hamcrest:3.0", - "org.mockito:mockito-core:5.21.0", + "org.mockito:mockito-core:5.23.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:jcl-over-slf4j:" + SLF4J_VERSION, "org.slf4j:slf4j-simple:" + SLF4J_VERSION, - "org.tukaani:xz:1.11", + "org.tukaani:xz:1.12", ], duplicate_version_warning = "warn", fail_on_missing_checksum = True, diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 57178519264..da5f7020b87 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,5 +1,5 @@ { - "lockFileVersion": 13, + "lockFileVersion": 26, "registryFileHashes": { "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", @@ -11,15 +11,21 @@ "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16", "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/MODULE.bazel": "d1086e248cda6576862b4b3fe9ad76a214e08c189af5b42557a6e1888812c5d5", - "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/source.json": "1b996859f840d8efc7c720efc61dcf2a84b1261cb3974cbbe9b6666ebf567775", + "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1", + "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215", + "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/MODULE.bazel": "51f2312901470cdab0dbdf3b88c40cd21c62a7ed58a3de45b365ddc5b11bcab2", + "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/source.json": "cea3901d7e299da7320700abbaafe57a65d039f10d0d7ea601c4a66938ea4b0c", "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a", "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b", "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896", "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85", - "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": "517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b", - "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", + "https://bcr.bazel.build/modules/apple_support/1.21.0/MODULE.bazel": "ac1824ed5edf17dee2fdd4927ada30c9f8c3b520be1b5fd02a5da15bc10bff3e", + "https://bcr.bazel.build/modules/apple_support/1.21.1/MODULE.bazel": "5809fa3efab15d1f3c3c635af6974044bac8a4919c62238cce06acee8a8c11f1", + "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4", + "https://bcr.bazel.build/modules/apple_support/1.24.2/source.json": "2c22c9827093250406c5568da6c54e6fdf0ef06238def3d99c71b12feb057a8d", "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.10.0/MODULE.bazel": "f75e8807570484a99be90abcd52b5e1f390362c258bcb73106f4544957a48101", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", "https://bcr.bazel.build/modules/bazel_features/1.13.0/MODULE.bazel": "c14c33c7c3c730612bdbe14ebbb5e61936b6f11322ea95a6e91cd1ba962f94df", "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", @@ -28,11 +34,15 @@ "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.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a", + "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9", "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", - "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://bcr.bazel.build/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6", + "https://bcr.bazel.build/modules/bazel_features/1.36.0/MODULE.bazel": "596cb62090b039caf1cad1d52a8bc35cf188ca9a4e279a828005e7ee49a1bec3", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080", + "https://bcr.bazel.build/modules/bazel_features/1.42.1/source.json": "fcd4396b2df85f64f2b3bb436ad870793ecf39180f1d796f913cc9276d355309", "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", @@ -45,56 +55,70 @@ "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/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.2/source.json": "34a3c8bcf233b835eb74be9d628899bb32999d3e0eadef1947a0a562a2b16ffb", "https://bcr.bazel.build/modules/bazel_worker_api/0.0.1/MODULE.bazel": "02a13b77321773b2042e70ee5e4c5e099c8ddee4cf2da9cd420442c36938d4bd", "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/MODULE.bazel": "460aa12d01231a80cce03c548287b433b321d205b0028ae596728c35e5ee442e", - "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/source.json": "d353c410d47a8b65d09fa98e83d57ebec257a2c2b9c6e42d6fda1cb25e5464a5", + "https://bcr.bazel.build/modules/bazel_worker_api/0.0.8/MODULE.bazel": "396c1ef53835aafe3d42ce6619080531ee770648303731f16cfaa33fa056bf0c", + "https://bcr.bazel.build/modules/bazel_worker_api/0.0.8/source.json": "abaf8ac9d2ab2f47bda9af4c0c080ff7907378888e1f4bc62a0539dd13ba61e8", "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/MODULE.bazel": "82494a01018bb7ef06d4a17ec4cd7a758721f10eb8b6c820a818e70d669500db", - "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/source.json": "a2d30458fd86cf022c2b6331e652526fa08e17573b2f5034a9dbcacdf9c2583c", - "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/bazel_worker_java/0.0.8/MODULE.bazel": "e76479eae70bd4e8f5f4c2dfc5d03ab971cfb18750246c7b3f3454c5c2ee6629", + "https://bcr.bazel.build/modules/bazel_worker_java/0.0.8/source.json": "9395c4679444bc47bf7e51a710366a4480aa371c6f6bed01868e2fabcf11acec", + "https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f", + "https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd", "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8", "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", "https://bcr.bazel.build/modules/gazelle/0.40.0/MODULE.bazel": "42ba5378ebe845fca43989a53186ab436d956db498acde790685fe0e8f9c6146", - "https://bcr.bazel.build/modules/gazelle/0.40.0/source.json": "1e5ef6e4d8b9b6836d93273c781e78ff829ea2e077afef7a57298040fa4f010a", + "https://bcr.bazel.build/modules/gazelle/0.47.0/MODULE.bazel": "b61bb007c4efad134aa30ee7f4a8e2a39b22aa5685f005edaa022fbd1de43ebc", + "https://bcr.bazel.build/modules/gazelle/0.47.0/source.json": "aeb2e5df14b7fb298625d75d08b9c65bdb0b56014c5eb89da9e5dd0572280ae6", "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/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", - "https://bcr.bazel.build/modules/googletest/1.15.2/source.json": "dbdda654dcb3a0d7a8bc5d0ac5fc7e150b58c2a986025ae5bc634bb2cb61f470", + "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", + "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/source.json": "f448c6e8963fdfa7eb831457df83ad63d3d6355018f6574fb017e8169deb43a9", + "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/MODULE.bazel": "ef4f9439e3270fdd6b9fd4dbc3d2f29d13888e44c529a1b243f7a31dfbc2e8e4", "https://bcr.bazel.build/modules/package_metadata/0.0.7/MODULE.bazel": "7adb03933fc8401f495800cf4eafcff0edc6da0ff55c7db223ef69d19f689486", "https://bcr.bazel.build/modules/package_metadata/0.0.7/source.json": "50639625e937b56115012674c797cca7a05a96b4878c87d803c13dc2b31de8a0", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", - "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", "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/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", + "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96", "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a", "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12", "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/27.2/MODULE.bazel": "32450b50673882e4c8c3d10a83f3bc82161b213ed2f80d17e38bece8f165c295", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2.bcr.1/MODULE.bazel": "52f4126f63a2f0bbf36b99c2a87648f08467a4eaf92ba726bc7d6a500bbf770c", "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95", "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", "https://bcr.bazel.build/modules/protobuf/31.1/MODULE.bazel": "379a389bb330b7b8c1cdf331cc90bf3e13de5614799b3b52cdb7c6f389f6b38e", - "https://bcr.bazel.build/modules/protobuf/31.1/source.json": "25af5d0219da0c0fc4d1191a24ce438e6ca7f49d2e1a94f354efeba6ef10426f", + "https://bcr.bazel.build/modules/protobuf/32.1/MODULE.bazel": "89cd2866a9cb07fee9ff74c41ceace11554f32e0d849de4e23ac55515cfada4d", + "https://bcr.bazel.build/modules/protobuf/33.4/MODULE.bazel": "114775b816b38b6d0ca620450d6b02550c60ceedfdc8d9a229833b34a223dc42", + "https://bcr.bazel.build/modules/protobuf/33.4/source.json": "555f8686b4c7d6b5ba731fbea13bf656b4bfd9a7ff629c1d9d3f6e1d6155de79", "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34", "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680", @@ -104,9 +128,11 @@ "https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa", "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", "https://bcr.bazel.build/modules/rules_android/0.6.6/MODULE.bazel": "b0fb569752aab65ab1a9db0a8f6cfaf5aa1754965e17e95dcf0e4d88e192a68d", - "https://bcr.bazel.build/modules/rules_android/0.6.6/source.json": "a9d8dc2d5a102dc03269a94acc886a4cab82cdcb9ccbc77b0f665d6d17a6ae09", + "https://bcr.bazel.build/modules/rules_android/0.7.1/MODULE.bazel": "a806fc382a774252f228a40e3b11b9fcc6276f8778c7fb33e9f72937c6258363", + "https://bcr.bazel.build/modules/rules_android/0.7.1/source.json": "151440aed3f0f73a00d4ed5cec5d31f63a6fef9b95d8fab1eb1810150fa525f2", "https://bcr.bazel.build/modules/rules_apple/3.16.0/MODULE.bazel": "0d1caf0b8375942ce98ea944be754a18874041e4e0459401d925577624d3a54a", - "https://bcr.bazel.build/modules/rules_apple/3.16.0/source.json": "d8b5fe461272018cc07cfafce11fe369c7525330804c37eec5a82f84cd475366", + "https://bcr.bazel.build/modules/rules_apple/4.1.0/MODULE.bazel": "76e10fd4a48038d3fc7c5dc6e63b7063bbf5304a2e3bd42edda6ec660eebea68", + "https://bcr.bazel.build/modules/rules_apple/4.1.0/source.json": "8ee81e1708756f81b343a5eb2b2f0b953f1d25c4ab3d4a68dc02754872e80715", "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", @@ -118,8 +144,14 @@ "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_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0", + "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", + "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", + "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37", "https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8", - "https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54", + "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84", + "https://bcr.bazel.build/modules/rules_cc/0.2.17/source.json": "3832f45d145354049137c0090df04629d9c2b5493dc5c2bf46f1834040133a07", + "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", "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_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8", @@ -127,7 +159,10 @@ "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd", "https://bcr.bazel.build/modules/rules_go/0.50.1/MODULE.bazel": "b91a308dc5782bb0a8021ad4330c81fea5bda77f96b9e4c117b9b9c8f6665ee0", "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/MODULE.bazel": "edfc3a9cea7bedb0eaaff37b0d7817c1a4bf72b3c615580b0ffcee6c52690fd4", - "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/source.json": "6b5cd0b3da2bd0e6949580851db990a04af0a285f072b9a0f059424457cd8cc9", + "https://bcr.bazel.build/modules/rules_go/0.53.0/MODULE.bazel": "a4ed760d3ac0dbc0d7b967631a9a3fd9100d28f7d9fcf214b4df87d4bfff5f9a", + "https://bcr.bazel.build/modules/rules_go/0.59.0/MODULE.bazel": "b7e43e7414a3139a7547d1b4909b29085fbe5182b6c58cbe1ed4c6272815aeae", + "https://bcr.bazel.build/modules/rules_go/0.60.0/MODULE.bazel": "4a57ff2ffc2a3570e3c5646575c5a4b07287e91bcdac5d1f72383d51502b48cb", + "https://bcr.bazel.build/modules/rules_go/0.60.0/source.json": "1e21368c5e0c3013a110bd79a8fcff8ca46b5bcb2b561713a7273cbfcff7c464", "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.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963", @@ -138,14 +173,14 @@ "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", "https://bcr.bazel.build/modules/rules_java/7.4.0/MODULE.bazel": "a592852f8a3dd539e82ee6542013bf2cadfc4c6946be8941e189d224500a8934", "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", - "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", - "https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad", "https://bcr.bazel.build/modules/rules_java/8.13.0/MODULE.bazel": "0444ebf737d144cf2bb2ccb368e7f1cce735264285f2a3711785827c1686625e", - "https://bcr.bazel.build/modules/rules_java/8.13.0/source.json": "4605c0f676b87dd9d1fabd4d743b71f04d97503bd1a79aad53f87399fb5396de", "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71", "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", + "https://bcr.bazel.build/modules/rules_java/9.0.3/MODULE.bazel": "1f98ed015f7e744a745e0df6e898a7c5e83562d6b759dfd475c76456dda5ccea", + "https://bcr.bazel.build/modules/rules_java/9.3.0/MODULE.bazel": "f657c72d65ac449caae9abf2e68e66c0d36f9416848c4c4903d0b3234229e7f2", + "https://bcr.bazel.build/modules/rules_java/9.3.0/source.json": "59ae7e662c3c7042b88bbb42ad12483523e234c65ebe4c51611baa43e85cb248", "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", @@ -155,6 +190,7 @@ "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", "https://bcr.bazel.build/modules/rules_jvm_external/6.6/MODULE.bazel": "153042249c7060536dc95b6bb9f9bb8063b8a0b0cb7acdb381bddbc2374aed55", "https://bcr.bazel.build/modules/rules_jvm_external/6.7/MODULE.bazel": "e717beabc4d091ecb2c803c2d341b88590e9116b8bf7947915eeb33aab4f96dd", + "https://bcr.bazel.build/modules/rules_jvm_external/6.9/MODULE.bazel": "07c5db05527db7744a54fcffd653e1550d40e0540207a7f7e6d0a4de5bef8274", "https://bcr.bazel.build/modules/rules_kotlin/1.9.5/MODULE.bazel": "043a16a572f610558ec2030db3ff0c9938574e7dd9f58bded1bb07c0192ef025", "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", "https://bcr.bazel.build/modules/rules_kotlin/2.1.3/MODULE.bazel": "ce7def6d576aa8d3a9c6d10e13b4d157296229674371f67dbf788dae0afae3d5", @@ -172,9 +208,9 @@ "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f", "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_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96", + "https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e", "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", - "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", "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", @@ -184,17 +220,24 @@ "https://bcr.bazel.build/modules/rules_python/0.37.2/MODULE.bazel": "b5ffde91410745750b6c13be1c5dc4555ef5bc50562af4a89fd77807fdde626a", "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43", - "https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917", + "https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13", + "https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6", + "https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8", + "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", + "https://bcr.bazel.build/modules/rules_python/1.7.0/source.json": "028a084b65dcf8f4dc4f82f8778dbe65df133f234b316828a82e060d81bdce32", "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251", "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/source.json": "37c10335f2361c337c5c1f34ed36d2da70534c23088062b33a8bdaab68aa9dea", "https://bcr.bazel.build/modules/rules_shell/0.1.2/MODULE.bazel": "66e4ca3ce084b04af0b9ff05ff14cab4e5df7503973818bb91cbc6cda08d32fc", "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.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", - "https://bcr.bazel.build/modules/rules_shell/0.4.1/source.json": "4757bd277fe1567763991c4425b483477bb82e35e777a56fd846eb5cceda324a", + "https://bcr.bazel.build/modules/rules_shell/0.6.1/MODULE.bazel": "72e76b0eea4e81611ef5452aa82b3da34caca0c8b7b5c0c9584338aa93bae26b", + "https://bcr.bazel.build/modules/rules_shell/0.6.1/source.json": "20ec05cd5e592055e214b2da8ccb283c7f2a421ea0dc2acbf1aa792e11c03d0c", "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca", "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", - "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186", + "https://bcr.bazel.build/modules/rules_swift/2.4.0/MODULE.bazel": "1639617eb1ede28d774d967a738b4a68b0accb40650beadb57c21846beab5efd", + "https://bcr.bazel.build/modules/rules_swift/3.1.2/MODULE.bazel": "72c8f5cf9d26427cee6c76c8e3853eb46ce6b0412a081b2b6db6e8ad56267400", + "https://bcr.bazel.build/modules/rules_swift/3.1.2/source.json": "e85761f3098a6faf40b8187695e3de6d97944e98abd0d8ce579cb2daf6319a66", "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.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd", @@ -202,254 +245,99 @@ "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", - "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/source.json": "5fba48bbe0ba48761f9e9f75f92876cafb5d07c0ce059cc7a8027416de94a05b", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", - "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" }, "selectedYankedVersions": {}, "moduleExtensions": { - "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { + "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { "general": { - "bzlTransitiveDigest": "ltCGFbl/LQQZXn/LEMXfKX7pGwyqNiOCHcmiQW0tmjM=", - "usagesDigest": "eXsWd8YDJDt7+F94YtjKuTAIRMWBi9JLS8hUiqynRIY=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_apple_cc_toolchains": { - "bzlFile": "@@apple_support~//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf_toolchains", - "attributes": {} - }, - "local_config_apple_cc": { - "bzlFile": "@@apple_support~//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "apple_support~", - "bazel_tools", - "bazel_tools" - ] - ] - } - }, - "@@pybind11_bazel~//:internal_configure.bzl%internal_configure_extension": { - "general": { - "bzlTransitiveDigest": "CyAKLVVonohnkTSqg9II/HA7M49sOlnMkgMHL3CmDuc=", - "usagesDigest": "mFrTHX5eCiNU/OIIGVHH3cOILY9Zmjqk8RQYv8o6Thk=", - "recordedFileInputs": { - "@@pybind11_bazel~//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" - }, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "06cynZ1bCvvy8zHPrrDlXq+Z68xmjctHpfFxi+zEpJY=", + "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=", + "recordedInputs": [ + "REPO_MAPPING:pybind11_bazel+,bazel_tools bazel_tools", + "FILE:@@pybind11_bazel+//MODULE.bazel e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" + ], "generatedRepoSpecs": { "pybind11": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "build_file": "@@pybind11_bazel~//:pybind11-BUILD.bazel", + "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel", "strip_prefix": "pybind11-2.12.0", "urls": [ "https://github.com/pybind/pybind11/archive/v2.12.0.zip" ] } } - }, - "recordedRepoMappingEntries": [ - [ - "pybind11_bazel~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_android~//bzlmod_extensions:apksig.bzl%apksig_extension": { + "@@rules_android+//bzlmod_extensions:apksig.bzl%apksig_extension": { "general": { - "bzlTransitiveDigest": "+fNvC5PNWx1aA64JjkW33+1zGbG9xgfi70xQhxbglhY=", - "usagesDigest": "TaGkNxVMBZxl1ANdUNPmIjKrA33bO+BpI06yTlpHdos=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "KrgiB8lWxqVdbipL9YIYOuGjS80xlZIM/EBvUg8SVd0=", + "usagesDigest": "zr/niBQ/s2fHozWAsg4vI70wAxcuFjG+QtM15qGkq9o=", + "recordedInputs": [ + "REPO_MAPPING:rules_android+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "apksig": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://android.googlesource.com/platform/tools/apksig/+archive/24e3075e68ebe17c0b529bb24bfda819db5e2f3b.tar.gz", - "build_file": "@@rules_android~//bzlmod_extensions:apksig.BUILD" + "build_file": "@@rules_android+//bzlmod_extensions:apksig.BUILD" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_android~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_android~//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": { + "@@rules_android+//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": { "general": { - "bzlTransitiveDigest": "/KJvxHLYhvSLJihEHN0e5Uzdd7OOMvpFb0BFUl1RUTs=", - "usagesDigest": "fh77SU1OUlWN5ivrGpY93+t0MipuVj89/MMUgfTpSa8=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "WYXjwqaZbEnV+ZWsKE3oDMpF5XVw8hxzet83NtyT8TM=", + "usagesDigest": "c1Y/KGGjUYCyd8zNIVTUh1bynVXRFz6xGKaSCBpQANM=", + "recordedInputs": [ + "REPO_MAPPING:rules_android+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "com_android_dex": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "url": "https://android.googlesource.com/platform/dalvik/+archive/5a81c499a569731e2395f7c8d13c0e0d4e17a2b6.tar.gz", - "build_file": "@@rules_android~//bzlmod_extensions:com_android_dex.BUILD" + "build_file": "@@rules_android+//bzlmod_extensions:com_android_dex.BUILD" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_android~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_android~//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": { + "@@rules_android+//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": { "general": { - "bzlTransitiveDigest": "NAy+0M15JNVEBb8Tny6t7j3lKqTnsAMjoBB6LJ+C370=", - "usagesDigest": "weZLGEpNa+fTJZ9CEljWxpN3/kuPzj/ULgebzOt2h4g=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "+rMrzIrv7sImYmkbXJYv+gFpTJQ79X3MpwwMLI2A+oA=", + "usagesDigest": "iEGI2aNDMkHt9LXCdViLNUUOslpiVj2DrevWWXZEFnU=", + "recordedInputs": [], "generatedRepoSpecs": { "androidsdk": { - "bzlFile": "@@rules_android~//rules/android_sdk_repository:rule.bzl", - "ruleClassName": "_android_sdk_repository", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [] - } - }, - "@@rules_apple~//apple:apple.bzl%provisioning_profile_repository_extension": { - "general": { - "bzlTransitiveDigest": "OLmLOE2zg0CXXzAR24XTccdOw39pMG2gG6R1VFOgDsE=", - "usagesDigest": "cLx5XGjlbSDOpyA053y/jlr4GcaXFVTeHQic6eyG38E=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_provisioning_profiles": { - "bzlFile": "@@rules_apple~//apple/internal:local_provisioning_profiles.bzl", - "ruleClassName": "provisioning_profile_repository", + "repoRuleId": "@@rules_android+//rules/android_sdk_repository:rule.bzl%_android_sdk_repository", "attributes": {} } - }, - "recordedRepoMappingEntries": [ - [ - "apple_support~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_apple~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_apple~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_apple~", - "build_bazel_apple_support", - "apple_support~" - ], - [ - "rules_apple~", - "build_bazel_rules_swift", - "rules_swift~" - ], - [ - "rules_swift~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_swift~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_swift~", - "build_bazel_apple_support", - "apple_support~" - ], - [ - "rules_swift~", - "build_bazel_rules_swift", - "rules_swift~" - ], - [ - "rules_swift~", - "build_bazel_rules_swift_local_config", - "rules_swift~~non_module_deps~build_bazel_rules_swift_local_config" - ] - ] - } - }, - "@@rules_apple~//apple:extensions.bzl%non_module_deps": { - "general": { - "bzlTransitiveDigest": "LJ3bhNqfW9y6MZFgtKQoPJyUMg/aEZ8H9QXSzK1VOBk=", - "usagesDigest": "5FfEPy/Z0Y2V9RbdJRDabgADFdvlfIIrps/5XYOnMNI=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "xctestrunner": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/google/xctestrunner/archive/b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6.tar.gz" - ], - "strip_prefix": "xctestrunner-b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6", - "sha256": "ae3a063c985a8633cb7eb566db21656f8db8eb9a0edb8c182312c7f0db53730d" - } - } - }, - "recordedRepoMappingEntries": [ - [ - "rules_apple~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { - "bzlTransitiveDigest": "BSndOxBXlbe5qZf1NRxf828dpEK6tM429pCnaFoUFYs=", - "usagesDigest": "Dg5Nih77FaLAipQB7wgwsAy553a3po0eNGQVTZKgCM8=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "m2i9p9Fn+7u7WGI0mz6K5GlmmtUuwReSjDHIISY08GI=", + "usagesDigest": "qTwqmKKUfWcPdvM0waG+CPWrxsbeAWVeUxavm7tEk9E=", + "recordedInputs": [ + "REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "com_github_jetbrains_kotlin_git": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", - "ruleClassName": "kotlin_compiler_git_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", "attributes": { "urls": [ "https://github.com/JetBrains/kotlin/releases/download/v2.1.0/kotlin-compiler-2.1.0.zip" @@ -458,16 +346,14 @@ } }, "com_github_jetbrains_kotlin": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", - "ruleClassName": "kotlin_capabilities_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", "attributes": { "git_repository_name": "com_github_jetbrains_kotlin_git", "compiler_version": "2.1.0" } }, "com_github_google_ksp": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl", - "ruleClassName": "ksp_compiler_plugin_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", "attributes": { "urls": [ "https://github.com/google/ksp/releases/download/2.1.0-1.0.28/artifacts.zip" @@ -477,8 +363,7 @@ } }, "com_github_pinterest_ktlint": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", "attributes": { "sha256": "a9f923be58fbd32670a17f0b729b1df804af882fa57402165741cb26e5440ca1", "urls": [ @@ -488,8 +373,7 @@ } }, "kotlinx_serialization_core_jvm": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "29c821a8d4e25cbfe4f2ce96cdd4526f61f8f4e69a135f9612a34a81d93b65f1", "urls": [ @@ -498,8 +382,7 @@ } }, "kotlinx_serialization_json": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "8c0016890a79ab5980dd520a5ab1a6738023c29aa3b6437c482e0e5fdc06dab1", "urls": [ @@ -508,8 +391,7 @@ } }, "kotlinx_serialization_json_jvm": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "d3234179bcff1886d53d67c11eca47f7f3cf7b63c349d16965f6db51b7f3dd9a", "urls": [ @@ -517,2772 +399,532 @@ ] } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_kotlin~", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, - "@@rules_python~//python/extensions:pip.bzl%pip": { + "@@rules_python+//python/extensions:config.bzl%config": { "general": { - "bzlTransitiveDigest": "AMoojKsX4Iw9GcO0xHbXz11GhPs9wzQ+Ua4OZ3muUzw=", - "usagesDigest": "ZVqDJcq4jlkbKBvSiotiO7ElR126/eiKOiKURsvOcoA=", - "recordedFileInputs": { - "@@rules_python~//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d", - "@@rules_python~//tools/publish/requirements_windows.txt": "7673adc71dc1a81d3661b90924d7a7c0fc998cd508b3cb4174337cef3f2de556", - "@@rules_python~//tools/publish/requirements_darwin.txt": "2994136eab7e57b083c3de76faf46f70fad130bc8e7360a7fed2b288b69e79dc" - }, - "recordedDirentsInputs": {}, - "envVariables": { - "RULES_PYTHON_REPO_DEBUG": null, - "RULES_PYTHON_REPO_DEBUG_VERBOSITY": null - }, + "bzlTransitiveDigest": "2hLgIvNVTLgxus0ZuXtleBe70intCfo0cHs8qvt6cdM=", + "usagesDigest": "ZVSXMAGpD+xzVNPuvF1IoLBkty7TROO0+akMapt1pAg=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,pypi__build rules_python++config+pypi__build", + "REPO_MAPPING:rules_python+,pypi__click rules_python++config+pypi__click", + "REPO_MAPPING:rules_python+,pypi__colorama rules_python++config+pypi__colorama", + "REPO_MAPPING:rules_python+,pypi__importlib_metadata rules_python++config+pypi__importlib_metadata", + "REPO_MAPPING:rules_python+,pypi__installer rules_python++config+pypi__installer", + "REPO_MAPPING:rules_python+,pypi__more_itertools rules_python++config+pypi__more_itertools", + "REPO_MAPPING:rules_python+,pypi__packaging rules_python++config+pypi__packaging", + "REPO_MAPPING:rules_python+,pypi__pep517 rules_python++config+pypi__pep517", + "REPO_MAPPING:rules_python+,pypi__pip rules_python++config+pypi__pip", + "REPO_MAPPING:rules_python+,pypi__pip_tools rules_python++config+pypi__pip_tools", + "REPO_MAPPING:rules_python+,pypi__pyproject_hooks rules_python++config+pypi__pyproject_hooks", + "REPO_MAPPING:rules_python+,pypi__setuptools rules_python++config+pypi__setuptools", + "REPO_MAPPING:rules_python+,pypi__tomli rules_python++config+pypi__tomli", + "REPO_MAPPING:rules_python+,pypi__wheel rules_python++config+pypi__wheel", + "REPO_MAPPING:rules_python+,pypi__zipp rules_python++config+pypi__zipp" + ], "generatedRepoSpecs": { - "rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "backports.tarfile-1.2.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "backports-tarfile==1.2.0", - "sha256": "77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", - "urls": [ - "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "backports_tarfile-1.2.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "backports-tarfile==1.2.0", - "sha256": "d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", - "urls": [ - "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_certifi_py3_none_any_922820b5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "certifi-2024.8.30-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "certifi==2024.8.30", - "sha256": "922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", - "urls": [ - "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_certifi_sdist_bec941d2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "certifi-2024.8.30.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "certifi==2024.8.30", - "sha256": "bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", - "urls": [ - "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", - "urls": [ - "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", - "urls": [ - "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" - ] - } - }, - "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", - "urls": [ - "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl" - ] - } - }, - "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", - "urls": [ - "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", - "urls": [ - "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", - "urls": [ - "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_cffi_sdist_1c39c601": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "cffi-1.17.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cffi==1.17.1", - "sha256": "1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", - "urls": [ - "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", - "urls": [ - "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", - "urls": [ - "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", - "urls": [ - "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", - "urls": [ - "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", - "urls": [ - "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", - "urls": [ - "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", - "urls": [ - "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", - "urls": [ - "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", - "urls": [ - "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", - "urls": [ - "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", - "urls": [ - "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", - "urls": [ - "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "charset_normalizer-3.4.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", - "urls": [ - "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_charset_normalizer_sdist_223217c3": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "charset_normalizer-3.4.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "charset-normalizer==3.4.0", - "sha256": "223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", - "urls": [ - "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "rules_python_internal": { + "repoRuleId": "@@rules_python+//python/private:internal_config_repo.bzl%internal_config_repo", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", - "urls": [ - "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", - "urls": [ - "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" - ] + "transition_setting_generators": {}, + "transition_settings": [] } }, - "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__build": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", - "urls": [ - "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl" - ] + "url": "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl", + "sha256": "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__click": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", - "urls": [ - "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl" - ] + "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", + "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__colorama": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", - "urls": [ - "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl" - ] + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__importlib_metadata": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", - "urls": [ - "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl" - ] + "url": "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl", + "sha256": "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_cryptography_sdist_315b9001": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__installer": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "cryptography-43.0.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "cryptography==43.0.3", - "sha256": "315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", - "urls": [ - "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz" - ] + "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl", + "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__more_itertools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "docutils-0.21.2-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "docutils==0.21.2", - "sha256": "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", - "urls": [ - "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl" - ] + "url": "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl", + "sha256": "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_docutils_sdist_3a6b1873": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__packaging": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "docutils-0.21.2.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "docutils==0.21.2", - "sha256": "3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", - "urls": [ - "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz" - ] + "url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", + "sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_idna_py3_none_any_946d195a": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__pep517": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "idna-3.10-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "idna==3.10", - "sha256": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", - "urls": [ - "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl" - ] + "url": "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl", + "sha256": "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_idna_sdist_12f65c9b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__pip": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "idna-3.10.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "idna==3.10", - "sha256": "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", - "urls": [ - "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz" - ] + "url": "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl", + "sha256": "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__pip_tools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "importlib_metadata-8.5.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "importlib-metadata==8.5.0", - "sha256": "45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", - "urls": [ - "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl" - ] + "url": "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl", + "sha256": "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_importlib_metadata_sdist_71522656": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__pyproject_hooks": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "importlib_metadata-8.5.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "importlib-metadata==8.5.0", - "sha256": "71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", - "urls": [ - "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz" - ] + "url": "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl", + "sha256": "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__setuptools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "jaraco.classes-3.4.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jaraco-classes==3.4.0", - "sha256": "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", - "urls": [ - "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl" - ] + "url": "https://files.pythonhosted.org/packages/90/99/158ad0609729111163fc1f674a5a42f2605371a4cf036d0441070e2f7455/setuptools-78.1.1-py3-none-any.whl", + "sha256": "c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__tomli": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "jaraco.classes-3.4.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jaraco-classes==3.4.0", - "sha256": "47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", - "urls": [ - "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz" - ] + "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", + "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__wheel": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "jaraco.context-6.0.1-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jaraco-context==6.0.1", - "sha256": "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", - "urls": [ - "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl" - ] + "url": "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl", + "sha256": "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } }, - "rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "pypi__zipp": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "jaraco_context-6.0.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jaraco-context==6.0.1", - "sha256": "9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", - "urls": [ - "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz" - ] + "url": "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl", + "sha256": "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" } - }, - "rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + } + } + } + }, + "@@rules_python+//python/uv:uv.bzl%uv": { + "general": { + "bzlTransitiveDigest": "ijW9KS7qsIY+yBVvJ+Nr1mzwQox09j13DnE3iIwaeTM=", + "usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,platforms platforms" + ], + "generatedRepoSpecs": { + "uv": { + "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo", "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" + "toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'", + "toolchain_names": [ + "none" ], - "filename": "jaraco.functools-4.1.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jaraco-functools==4.1.0", - "sha256": "ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", - "urls": [ - "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "jaraco_functools-4.1.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jaraco-functools==4.1.0", - "sha256": "70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", - "urls": [ - "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "jeepney-0.8.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jeepney==0.8.0", - "sha256": "c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755", - "urls": [ - "https://files.pythonhosted.org/packages/ae/72/2a1e2290f1ab1e06f71f3d0f1646c9e4634e70e1d37491535e19266e8dc9/jeepney-0.8.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_jeepney_sdist_5efe48d2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "jeepney-0.8.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "jeepney==0.8.0", - "sha256": "5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", - "urls": [ - "https://files.pythonhosted.org/packages/d6/f4/154cf374c2daf2020e05c3c6a03c91348d59b23c5366e968feb198306fdf/jeepney-0.8.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_keyring_py3_none_any_5426f817": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "keyring-25.4.1-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "keyring==25.4.1", - "sha256": "5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf", - "urls": [ - "https://files.pythonhosted.org/packages/83/25/e6d59e5f0a0508d0dca8bb98c7f7fd3772fc943ac3f53d5ab18a218d32c0/keyring-25.4.1-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_keyring_sdist_b07ebc55": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "keyring-25.4.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "keyring==25.4.1", - "sha256": "b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b", - "urls": [ - "https://files.pythonhosted.org/packages/a5/1c/2bdbcfd5d59dc6274ffb175bc29aa07ecbfab196830e0cfbde7bd861a2ea/keyring-25.4.1.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "markdown_it_py-3.0.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "markdown-it-py==3.0.0", - "sha256": "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", - "urls": [ - "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "markdown-it-py-3.0.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "markdown-it-py==3.0.0", - "sha256": "e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", - "urls": [ - "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_mdurl_py3_none_any_84008a41": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "mdurl-0.1.2-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "mdurl==0.1.2", - "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", - "urls": [ - "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_mdurl_sdist_bb413d29": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "mdurl-0.1.2.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "mdurl==0.1.2", - "sha256": "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", - "urls": [ - "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "more_itertools-10.5.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "more-itertools==10.5.0", - "sha256": "037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", - "urls": [ - "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_more_itertools_sdist_5482bfef": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "more-itertools-10.5.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "more-itertools==10.5.0", - "sha256": "5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6", - "urls": [ - "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", - "urls": [ - "https://files.pythonhosted.org/packages/b3/89/1daff5d9ba5a95a157c092c7c5f39b8dd2b1ddb4559966f808d31cfb67e0/nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", - "urls": [ - "https://files.pythonhosted.org/packages/2c/b6/42fc3c69cabf86b6b81e4c051a9b6e249c5ba9f8155590222c2622961f58/nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", - "urls": [ - "https://files.pythonhosted.org/packages/45/b9/833f385403abaf0023c6547389ec7a7acf141ddd9d1f21573723a6eab39a/nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", - "urls": [ - "https://files.pythonhosted.org/packages/05/2b/85977d9e11713b5747595ee61f381bc820749daf83f07b90b6c9964cf932/nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", - "urls": [ - "https://files.pythonhosted.org/packages/72/f2/5c894d5265ab80a97c68ca36f25c8f6f0308abac649aaf152b74e7e854a8/nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", - "urls": [ - "https://files.pythonhosted.org/packages/ab/a7/375afcc710dbe2d64cfbd69e31f82f3e423d43737258af01f6a56d844085/nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", - "urls": [ - "https://files.pythonhosted.org/packages/c2/a8/3bb02d0c60a03ad3a112b76c46971e9480efa98a8946677b5a59f60130ca/nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", - "urls": [ - "https://files.pythonhosted.org/packages/1b/63/6ab90d0e5225ab9780f6c9fb52254fa36b52bb7c188df9201d05b647e5e1/nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe", - "urls": [ - "https://files.pythonhosted.org/packages/a3/da/0c4e282bc3cff4a0adf37005fa1fb42257673fbc1bbf7d1ff639ec3d255a/nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", - "urls": [ - "https://files.pythonhosted.org/packages/de/81/c291231463d21da5f8bba82c8167a6d6893cc5419b0639801ee5d3aeb8a9/nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", - "urls": [ - "https://files.pythonhosted.org/packages/eb/61/73a007c74c37895fdf66e0edcd881f5eaa17a348ff02f4bb4bc906d61085/nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "nh3-0.2.18-cp37-abi3-win_amd64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", - "urls": [ - "https://files.pythonhosted.org/packages/26/8d/53c5b19c4999bdc6ba95f246f4ef35ca83d7d7423e5e38be43ad66544e5d/nh3-0.2.18-cp37-abi3-win_amd64.whl" - ] - } - }, - "rules_python_publish_deps_311_nh3_sdist_94a16692": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "nh3-0.2.18.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "nh3==0.2.18", - "sha256": "94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", - "urls": [ - "https://files.pythonhosted.org/packages/62/73/10df50b42ddb547a907deeb2f3c9823022580a7a47281e8eae8e003a9639/nh3-0.2.18.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "pkginfo-1.10.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pkginfo==1.10.0", - "sha256": "889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097", - "urls": [ - "https://files.pythonhosted.org/packages/56/09/054aea9b7534a15ad38a363a2bd974c20646ab1582a387a95b8df1bfea1c/pkginfo-1.10.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_pkginfo_sdist_5df73835": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "pkginfo-1.10.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pkginfo==1.10.0", - "sha256": "5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", - "urls": [ - "https://files.pythonhosted.org/packages/2f/72/347ec5be4adc85c182ed2823d8d1c7b51e13b9a6b0c1aae59582eca652df/pkginfo-1.10.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "pycparser-2.22-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pycparser==2.22", - "sha256": "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", - "urls": [ - "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_pycparser_sdist_491c8be9": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "pycparser-2.22.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pycparser==2.22", - "sha256": "491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", - "urls": [ - "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "pygments-2.18.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pygments==2.18.0", - "sha256": "b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", - "urls": [ - "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_pygments_sdist_786ff802": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "pygments-2.18.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pygments==2.18.0", - "sha256": "786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", - "urls": [ - "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_windows_x86_64" - ], - "filename": "pywin32_ctypes-0.2.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pywin32-ctypes==0.2.3", - "sha256": "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", - "urls": [ - "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "pywin32-ctypes-0.2.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "pywin32-ctypes==0.2.3", - "sha256": "d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", - "urls": [ - "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "readme_renderer-44.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "readme-renderer==44.0", - "sha256": "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", - "urls": [ - "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_readme_renderer_sdist_8712034e": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "readme_renderer-44.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "readme-renderer==44.0", - "sha256": "8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", - "urls": [ - "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_requests_py3_none_any_70761cfe": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "requests-2.32.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "requests==2.32.3", - "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", - "urls": [ - "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_requests_sdist_55365417": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "requests-2.32.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "requests==2.32.3", - "sha256": "55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", - "urls": [ - "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "requests_toolbelt-1.0.0-py2.py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "requests-toolbelt==1.0.0", - "sha256": "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", - "urls": [ - "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "requests-toolbelt-1.0.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "requests-toolbelt==1.0.0", - "sha256": "7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", - "urls": [ - "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "rfc3986-2.0.0-py2.py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "rfc3986==2.0.0", - "sha256": "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", - "urls": [ - "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_rfc3986_sdist_97aacf9d": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "rfc3986-2.0.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "rfc3986==2.0.0", - "sha256": "97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", - "urls": [ - "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_rich_py3_none_any_9836f509": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "rich-13.9.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "rich==13.9.3", - "sha256": "9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", - "urls": [ - "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_rich_sdist_bc1e01b8": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "rich-13.9.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "rich==13.9.3", - "sha256": "bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e", - "urls": [ - "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "filename": "SecretStorage-3.3.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "secretstorage==3.3.3", - "sha256": "f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", - "urls": [ - "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_secretstorage_sdist_2403533e": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "SecretStorage-3.3.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "secretstorage==3.3.3", - "sha256": "2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", - "urls": [ - "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_twine_py3_none_any_215dbe7b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "twine-5.1.1-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "twine==5.1.1", - "sha256": "215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997", - "urls": [ - "https://files.pythonhosted.org/packages/5d/ec/00f9d5fd040ae29867355e559a94e9a8429225a0284a3f5f091a3878bfc0/twine-5.1.1-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_twine_sdist_9aa08251": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "twine-5.1.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "twine==5.1.1", - "sha256": "9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db", - "urls": [ - "https://files.pythonhosted.org/packages/77/68/bd982e5e949ef8334e6f7dcf76ae40922a8750aa2e347291ae1477a4782b/twine-5.1.1.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "urllib3-2.2.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "urllib3==2.2.3", - "sha256": "ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", - "urls": [ - "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_urllib3_sdist_e7d814a8": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "urllib3-2.2.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "urllib3==2.2.3", - "sha256": "e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", - "urls": [ - "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz" - ] - } - }, - "rules_python_publish_deps_311_zipp_py3_none_any_a817ac80": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "filename": "zipp-3.20.2-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "zipp==3.20.2", - "sha256": "a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", - "urls": [ - "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl" - ] - } - }, - "rules_python_publish_deps_311_zipp_sdist_bc9eb26f": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", - "attributes": { - "dep_template": "@rules_python_publish_deps//{name}:{target}", - "experimental_target_platforms": [ - "cp311_linux_aarch64", - "cp311_linux_arm", - "cp311_linux_ppc", - "cp311_linux_s390x", - "cp311_linux_x86_64", - "cp311_osx_aarch64", - "cp311_osx_x86_64", - "cp311_windows_x86_64" - ], - "extra_pip_args": [ - "--index-url", - "https://pypi.org/simple" - ], - "filename": "zipp-3.20.2.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", - "repo": "rules_python_publish_deps_311", - "requirement": "zipp==3.20.2", - "sha256": "bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", - "urls": [ - "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz" - ] - } - }, - "rules_python_publish_deps": { - "bzlFile": "@@rules_python~//python/private/pypi:hub_repository.bzl", - "ruleClassName": "hub_repository", - "attributes": { - "repo_name": "rules_python_publish_deps", - "extra_hub_aliases": {}, - "whl_map": { - "backports_tarfile": "{\"rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7\":[{\"filename\":\"backports.tarfile-1.2.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2\":[{\"filename\":\"backports_tarfile-1.2.0.tar.gz\",\"version\":\"3.11\"}]}", - "certifi": "{\"rules_python_publish_deps_311_certifi_py3_none_any_922820b5\":[{\"filename\":\"certifi-2024.8.30-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_certifi_sdist_bec941d2\":[{\"filename\":\"certifi-2024.8.30.tar.gz\",\"version\":\"3.11\"}]}", - "cffi": "{\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_sdist_1c39c601\":[{\"filename\":\"cffi-1.17.1.tar.gz\",\"version\":\"3.11\"}]}", - "charset_normalizer": "{\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe\":[{\"filename\":\"charset_normalizer-3.4.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_sdist_223217c3\":[{\"filename\":\"charset_normalizer-3.4.0.tar.gz\",\"version\":\"3.11\"}]}", - "cryptography": "{\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_sdist_315b9001\":[{\"filename\":\"cryptography-43.0.3.tar.gz\",\"version\":\"3.11\"}]}", - "docutils": "{\"rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9\":[{\"filename\":\"docutils-0.21.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_docutils_sdist_3a6b1873\":[{\"filename\":\"docutils-0.21.2.tar.gz\",\"version\":\"3.11\"}]}", - "idna": "{\"rules_python_publish_deps_311_idna_py3_none_any_946d195a\":[{\"filename\":\"idna-3.10-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_idna_sdist_12f65c9b\":[{\"filename\":\"idna-3.10.tar.gz\",\"version\":\"3.11\"}]}", - "importlib_metadata": "{\"rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197\":[{\"filename\":\"importlib_metadata-8.5.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_importlib_metadata_sdist_71522656\":[{\"filename\":\"importlib_metadata-8.5.0.tar.gz\",\"version\":\"3.11\"}]}", - "jaraco_classes": "{\"rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b\":[{\"filename\":\"jaraco.classes-3.4.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5\":[{\"filename\":\"jaraco.classes-3.4.0.tar.gz\",\"version\":\"3.11\"}]}", - "jaraco_context": "{\"rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48\":[{\"filename\":\"jaraco.context-6.0.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5\":[{\"filename\":\"jaraco_context-6.0.1.tar.gz\",\"version\":\"3.11\"}]}", - "jaraco_functools": "{\"rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13\":[{\"filename\":\"jaraco.functools-4.1.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2\":[{\"filename\":\"jaraco_functools-4.1.0.tar.gz\",\"version\":\"3.11\"}]}", - "jeepney": "{\"rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad\":[{\"filename\":\"jeepney-0.8.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jeepney_sdist_5efe48d2\":[{\"filename\":\"jeepney-0.8.0.tar.gz\",\"version\":\"3.11\"}]}", - "keyring": "{\"rules_python_publish_deps_311_keyring_py3_none_any_5426f817\":[{\"filename\":\"keyring-25.4.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_keyring_sdist_b07ebc55\":[{\"filename\":\"keyring-25.4.1.tar.gz\",\"version\":\"3.11\"}]}", - "markdown_it_py": "{\"rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684\":[{\"filename\":\"markdown_it_py-3.0.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94\":[{\"filename\":\"markdown-it-py-3.0.0.tar.gz\",\"version\":\"3.11\"}]}", - "mdurl": "{\"rules_python_publish_deps_311_mdurl_py3_none_any_84008a41\":[{\"filename\":\"mdurl-0.1.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_mdurl_sdist_bb413d29\":[{\"filename\":\"mdurl-0.1.2.tar.gz\",\"version\":\"3.11\"}]}", - "more_itertools": "{\"rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32\":[{\"filename\":\"more_itertools-10.5.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_more_itertools_sdist_5482bfef\":[{\"filename\":\"more-itertools-10.5.0.tar.gz\",\"version\":\"3.11\"}]}", - "nh3": "{\"rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-win_amd64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_sdist_94a16692\":[{\"filename\":\"nh3-0.2.18.tar.gz\",\"version\":\"3.11\"}]}", - "pkginfo": "{\"rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2\":[{\"filename\":\"pkginfo-1.10.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pkginfo_sdist_5df73835\":[{\"filename\":\"pkginfo-1.10.0.tar.gz\",\"version\":\"3.11\"}]}", - "pycparser": "{\"rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d\":[{\"filename\":\"pycparser-2.22-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pycparser_sdist_491c8be9\":[{\"filename\":\"pycparser-2.22.tar.gz\",\"version\":\"3.11\"}]}", - "pygments": "{\"rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0\":[{\"filename\":\"pygments-2.18.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pygments_sdist_786ff802\":[{\"filename\":\"pygments-2.18.0.tar.gz\",\"version\":\"3.11\"}]}", - "pywin32_ctypes": "{\"rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337\":[{\"filename\":\"pywin32_ctypes-0.2.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04\":[{\"filename\":\"pywin32-ctypes-0.2.3.tar.gz\",\"version\":\"3.11\"}]}", - "readme_renderer": "{\"rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b\":[{\"filename\":\"readme_renderer-44.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_readme_renderer_sdist_8712034e\":[{\"filename\":\"readme_renderer-44.0.tar.gz\",\"version\":\"3.11\"}]}", - "requests": "{\"rules_python_publish_deps_311_requests_py3_none_any_70761cfe\":[{\"filename\":\"requests-2.32.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_requests_sdist_55365417\":[{\"filename\":\"requests-2.32.3.tar.gz\",\"version\":\"3.11\"}]}", - "requests_toolbelt": "{\"rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66\":[{\"filename\":\"requests_toolbelt-1.0.0-py2.py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3\":[{\"filename\":\"requests-toolbelt-1.0.0.tar.gz\",\"version\":\"3.11\"}]}", - "rfc3986": "{\"rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b\":[{\"filename\":\"rfc3986-2.0.0-py2.py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_rfc3986_sdist_97aacf9d\":[{\"filename\":\"rfc3986-2.0.0.tar.gz\",\"version\":\"3.11\"}]}", - "rich": "{\"rules_python_publish_deps_311_rich_py3_none_any_9836f509\":[{\"filename\":\"rich-13.9.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_rich_sdist_bc1e01b8\":[{\"filename\":\"rich-13.9.3.tar.gz\",\"version\":\"3.11\"}]}", - "secretstorage": "{\"rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662\":[{\"filename\":\"SecretStorage-3.3.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_secretstorage_sdist_2403533e\":[{\"filename\":\"SecretStorage-3.3.3.tar.gz\",\"version\":\"3.11\"}]}", - "twine": "{\"rules_python_publish_deps_311_twine_py3_none_any_215dbe7b\":[{\"filename\":\"twine-5.1.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_twine_sdist_9aa08251\":[{\"filename\":\"twine-5.1.1.tar.gz\",\"version\":\"3.11\"}]}", - "urllib3": "{\"rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0\":[{\"filename\":\"urllib3-2.2.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_urllib3_sdist_e7d814a8\":[{\"filename\":\"urllib3-2.2.3.tar.gz\",\"version\":\"3.11\"}]}", - "zipp": "{\"rules_python_publish_deps_311_zipp_py3_none_any_a817ac80\":[{\"filename\":\"zipp-3.20.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_zipp_sdist_bc9eb26f\":[{\"filename\":\"zipp-3.20.2.tar.gz\",\"version\":\"3.11\"}]}" - }, - "packages": [ - "backports_tarfile", - "certifi", - "charset_normalizer", - "docutils", - "idna", - "importlib_metadata", - "jaraco_classes", - "jaraco_context", - "jaraco_functools", - "keyring", - "markdown_it_py", - "mdurl", - "more_itertools", - "nh3", - "pkginfo", - "pygments", - "readme_renderer", - "requests", - "requests_toolbelt", - "rfc3986", - "rich", - "twine", - "urllib3", - "zipp" - ], - "groups": {} + "toolchain_implementations": { + "none": "'@@rules_python+//python:none'" + }, + "toolchain_compatible_with": { + "none": [ + "@platforms//:incompatible" + ] + }, + "toolchain_target_settings": {} } } - }, - "moduleExtensionMetadata": { - "useAllRepos": "NO", - "reproducible": false - }, - "recordedRepoMappingEntries": [ - [ - "bazel_features~", - "bazel_features_globals", - "bazel_features~~version_extension~bazel_features_globals" - ], - [ - "bazel_features~", - "bazel_features_version", - "bazel_features~~version_extension~bazel_features_version" - ], - [ - "rules_python~", - "bazel_features", - "bazel_features~" - ], - [ - "rules_python~", - "bazel_skylib", - "bazel_skylib~" - ], - [ - "rules_python~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_python~", - "pypi__build", - "rules_python~~internal_deps~pypi__build" - ], - [ - "rules_python~", - "pypi__click", - "rules_python~~internal_deps~pypi__click" - ], - [ - "rules_python~", - "pypi__colorama", - "rules_python~~internal_deps~pypi__colorama" - ], - [ - "rules_python~", - "pypi__importlib_metadata", - "rules_python~~internal_deps~pypi__importlib_metadata" - ], - [ - "rules_python~", - "pypi__installer", - "rules_python~~internal_deps~pypi__installer" - ], - [ - "rules_python~", - "pypi__more_itertools", - "rules_python~~internal_deps~pypi__more_itertools" - ], - [ - "rules_python~", - "pypi__packaging", - "rules_python~~internal_deps~pypi__packaging" - ], - [ - "rules_python~", - "pypi__pep517", - "rules_python~~internal_deps~pypi__pep517" - ], - [ - "rules_python~", - "pypi__pip", - "rules_python~~internal_deps~pypi__pip" - ], - [ - "rules_python~", - "pypi__pip_tools", - "rules_python~~internal_deps~pypi__pip_tools" - ], - [ - "rules_python~", - "pypi__pyproject_hooks", - "rules_python~~internal_deps~pypi__pyproject_hooks" - ], - [ - "rules_python~", - "pypi__setuptools", - "rules_python~~internal_deps~pypi__setuptools" - ], - [ - "rules_python~", - "pypi__tomli", - "rules_python~~internal_deps~pypi__tomli" - ], - [ - "rules_python~", - "pypi__wheel", - "rules_python~~internal_deps~pypi__wheel" - ], - [ - "rules_python~", - "pypi__zipp", - "rules_python~~internal_deps~pypi__zipp" - ], - [ - "rules_python~", - "pythons_hub", - "rules_python~~python~pythons_hub" - ], - [ - "rules_python~~python~pythons_hub", - "python_3_10_host", - "rules_python~~python~python_3_10_host" - ], - [ - "rules_python~~python~pythons_hub", - "python_3_11_host", - "rules_python~~python~python_3_11_host" - ], - [ - "rules_python~~python~pythons_hub", - "python_3_12_host", - "rules_python~~python~python_3_12_host" - ], - [ - "rules_python~~python~pythons_hub", - "python_3_9_host", - "rules_python~~python~python_3_9_host" - ] - ] + } } - }, - "@@rules_swift~//swift:extensions.bzl%non_module_deps": { - "general": { - "bzlTransitiveDigest": "vhXfCi07IAmWf5hLHcxh5xCtTwvEGrmMkOavEMD5pzs=", - "usagesDigest": "/dVEtCLqIAaLXjfRXsJupTS9pTgmYVN/tFdJlGgE5NA=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "com_github_apple_swift_protobuf": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-protobuf/archive/1.20.2.tar.gz" - ], - "sha256": "3fb50bd4d293337f202d917b6ada22f9548a0a0aed9d9a4d791e6fbd8a246ebb", - "strip_prefix": "swift-protobuf-1.20.2/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_protobuf/BUILD.overlay" - } - }, - "com_github_grpc_grpc_swift": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/grpc/grpc-swift/archive/1.16.0.tar.gz" - ], - "sha256": "58b60431d0064969f9679411264b82e40a217ae6bd34e17096d92cc4e47556a5", - "strip_prefix": "grpc-swift-1.16.0/", - "build_file": "@@rules_swift~//third_party:com_github_grpc_grpc_swift/BUILD.overlay" - } - }, - "com_github_apple_swift_docc_symbolkit": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-docc-symbolkit/archive/refs/tags/swift-5.10-RELEASE.tar.gz" - ], - "sha256": "de1d4b6940468ddb53b89df7aa1a81323b9712775b0e33e8254fa0f6f7469a97", - "strip_prefix": "swift-docc-symbolkit-swift-5.10-RELEASE", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay" - } - }, - "com_github_apple_swift_nio": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio/archive/2.42.0.tar.gz" - ], - "sha256": "e3304bc3fb53aea74a3e54bd005ede11f6dc357117d9b1db642d03aea87194a0", - "strip_prefix": "swift-nio-2.42.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_http2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-http2/archive/1.26.0.tar.gz" - ], - "sha256": "f0edfc9d6a7be1d587e5b403f2d04264bdfae59aac1d74f7d974a9022c6d2b25", - "strip_prefix": "swift-nio-http2-1.26.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_http2/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_transport_services": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-transport-services/archive/1.15.0.tar.gz" - ], - "sha256": "f3498dafa633751a52b9b7f741f7ac30c42bcbeb3b9edca6d447e0da8e693262", - "strip_prefix": "swift-nio-transport-services-1.15.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_extras": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-extras/archive/1.4.0.tar.gz" - ], - "sha256": "4684b52951d9d9937bb3e8ccd6b5daedd777021ef2519ea2f18c4c922843b52b", - "strip_prefix": "swift-nio-extras-1.4.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_extras/BUILD.overlay" - } - }, - "com_github_apple_swift_log": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-log/archive/1.4.4.tar.gz" - ], - "sha256": "48fe66426c784c0c20031f15dc17faf9f4c9037c192bfac2f643f65cb2321ba0", - "strip_prefix": "swift-log-1.4.4/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_log/BUILD.overlay" - } - }, - "com_github_apple_swift_nio_ssl": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-nio-ssl/archive/2.23.0.tar.gz" - ], - "sha256": "4787c63f61dd04d99e498adc3d1a628193387e41efddf8de19b8db04544d016d", - "strip_prefix": "swift-nio-ssl-2.23.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay" - } - }, - "com_github_apple_swift_collections": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-collections/archive/1.0.4.tar.gz" - ], - "sha256": "d9e4c8a91c60fb9c92a04caccbb10ded42f4cb47b26a212bc6b39cc390a4b096", - "strip_prefix": "swift-collections-1.0.4/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_collections/BUILD.overlay" - } - }, - "com_github_apple_swift_atomics": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "urls": [ - "https://github.com/apple/swift-atomics/archive/1.1.0.tar.gz" - ], - "sha256": "1bee7f469f7e8dc49f11cfa4da07182fbc79eab000ec2c17bfdce468c5d276fb", - "strip_prefix": "swift-atomics-1.1.0/", - "build_file": "@@rules_swift~//third_party:com_github_apple_swift_atomics/BUILD.overlay" - } - }, - "build_bazel_rules_swift_index_import": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "build_file": "@@rules_swift~//third_party:build_bazel_rules_swift_index_import/BUILD.overlay", - "canonical_id": "index-import-5.8", - "urls": [ - "https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz" - ], - "sha256": "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15" - } - }, - "build_bazel_rules_swift_local_config": { - "bzlFile": "@@rules_swift~//swift/internal:swift_autoconfiguration.bzl", - "ruleClassName": "swift_autoconfiguration", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "rules_swift~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_swift~", - "build_bazel_rules_swift", - "rules_swift~" - ] + } + }, + "facts": { + "@@rules_go+//go:extensions.bzl%go_sdk": { + "1.22.4": { + "aix_ppc64": [ + "go1.22.4.aix-ppc64.tar.gz", + "b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1" + ], + "darwin_amd64": [ + "go1.22.4.darwin-amd64.tar.gz", + "c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3" + ], + "darwin_arm64": [ + "go1.22.4.darwin-arm64.tar.gz", + "242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827" + ], + "dragonfly_amd64": [ + "go1.22.4.dragonfly-amd64.tar.gz", + "f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b" + ], + "freebsd_386": [ + "go1.22.4.freebsd-386.tar.gz", + "7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5" + ], + "freebsd_amd64": [ + "go1.22.4.freebsd-amd64.tar.gz", + "88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78" + ], + "freebsd_arm64": [ + "go1.22.4.freebsd-arm64.tar.gz", + "726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc" + ], + "freebsd_armv6l": [ + "go1.22.4.freebsd-arm.tar.gz", + "3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6" + ], + "freebsd_riscv64": [ + "go1.22.4.freebsd-riscv64.tar.gz", + "5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71" + ], + "illumos_amd64": [ + "go1.22.4.illumos-amd64.tar.gz", + "d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63" + ], + "linux_386": [ + "go1.22.4.linux-386.tar.gz", + "47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec" + ], + "linux_amd64": [ + "go1.22.4.linux-amd64.tar.gz", + "ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d" + ], + "linux_arm64": [ + "go1.22.4.linux-arm64.tar.gz", + "a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771" + ], + "linux_armv6l": [ + "go1.22.4.linux-armv6l.tar.gz", + "e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de" + ], + "linux_loong64": [ + "go1.22.4.linux-loong64.tar.gz", + "e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d" + ], + "linux_mips": [ + "go1.22.4.linux-mips.tar.gz", + "73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1" + ], + "linux_mips64": [ + "go1.22.4.linux-mips64.tar.gz", + "417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45" + ], + "linux_mips64le": [ + "go1.22.4.linux-mips64le.tar.gz", + "7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b" + ], + "linux_mipsle": [ + "go1.22.4.linux-mipsle.tar.gz", + "69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e" + ], + "linux_ppc64": [ + "go1.22.4.linux-ppc64.tar.gz", + "dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7" + ], + "linux_ppc64le": [ + "go1.22.4.linux-ppc64le.tar.gz", + "a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4" + ], + "linux_riscv64": [ + "go1.22.4.linux-riscv64.tar.gz", + "56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a" + ], + "linux_s390x": [ + "go1.22.4.linux-s390x.tar.gz", + "7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec" + ], + "netbsd_386": [ + "go1.22.4.netbsd-386.tar.gz", + "ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d" + ], + "netbsd_amd64": [ + "go1.22.4.netbsd-amd64.tar.gz", + "33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234" + ], + "netbsd_arm64": [ + "go1.22.4.netbsd-arm64.tar.gz", + "c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e" + ], + "netbsd_armv6l": [ + "go1.22.4.netbsd-arm.tar.gz", + "fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6" + ], + "openbsd_386": [ + "go1.22.4.openbsd-386.tar.gz", + "d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47" + ], + "openbsd_amd64": [ + "go1.22.4.openbsd-amd64.tar.gz", + "72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae" + ], + "openbsd_arm64": [ + "go1.22.4.openbsd-arm64.tar.gz", + "a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650" + ], + "openbsd_armv6l": [ + "go1.22.4.openbsd-arm.tar.gz", + "1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065" + ], + "openbsd_ppc64": [ + "go1.22.4.openbsd-ppc64.tar.gz", + "9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b" + ], + "plan9_386": [ + "go1.22.4.plan9-386.tar.gz", + "a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8" + ], + "plan9_amd64": [ + "go1.22.4.plan9-amd64.tar.gz", + "5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1" + ], + "plan9_armv6l": [ + "go1.22.4.plan9-arm.tar.gz", + "6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370" + ], + "solaris_amd64": [ + "go1.22.4.solaris-amd64.tar.gz", + "e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba" + ], + "windows_386": [ + "go1.22.4.windows-386.zip", + "aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25" + ], + "windows_amd64": [ + "go1.22.4.windows-amd64.zip", + "26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98" + ], + "windows_arm64": [ + "go1.22.4.windows-arm64.zip", + "8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed" + ], + "windows_armv6l": [ + "go1.22.4.windows-arm.zip", + "5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6" + ] + }, + "1.25.0": { + "aix_ppc64": [ + "go1.25.0.aix-ppc64.tar.gz", + "e5234a7dac67bc86c528fe9752fc9d63557918627707a733ab4cac1a6faed2d4" + ], + "darwin_amd64": [ + "go1.25.0.darwin-amd64.tar.gz", + "5bd60e823037062c2307c71e8111809865116714d6f6b410597cf5075dfd80ef" + ], + "darwin_arm64": [ + "go1.25.0.darwin-arm64.tar.gz", + "544932844156d8172f7a28f77f2ac9c15a23046698b6243f633b0a0b00c0749c" + ], + "dragonfly_amd64": [ + "go1.25.0.dragonfly-amd64.tar.gz", + "5ed3cf9a810a1483822538674f1336c06b51aa1b94d6d545a1a0319a48177120" + ], + "freebsd_386": [ + "go1.25.0.freebsd-386.tar.gz", + "abea5d5c6697e6b5c224731f2158fe87c602996a2a233ac0c4730cd57bf8374e" + ], + "freebsd_amd64": [ + "go1.25.0.freebsd-amd64.tar.gz", + "86e6fe0a29698d7601c4442052dac48bd58d532c51cccb8f1917df648138730b" + ], + "freebsd_arm": [ + "go1.25.0.freebsd-arm.tar.gz", + "d90b78e41921f72f30e8bbc81d9dec2cff7ff384a33d8d8debb24053e4336bfe" + ], + "freebsd_arm64": [ + "go1.25.0.freebsd-arm64.tar.gz", + "451d0da1affd886bfb291b7c63a6018527b269505db21ce6e14724f22ab0662e" + ], + "freebsd_riscv64": [ + "go1.25.0.freebsd-riscv64.tar.gz", + "7b565f76bd8bda46549eeaaefe0e53b251e644c230577290c0f66b1ecdb3cdbe" + ], + "illumos_amd64": [ + "go1.25.0.illumos-amd64.tar.gz", + "b1e1fdaab1ad25aa1c08d7a36c97d45d74b98b89c3f78c6d2145f77face54a2c" + ], + "linux_386": [ + "go1.25.0.linux-386.tar.gz", + "8c602dd9d99bc9453b3995d20ce4baf382cc50855900a0ece5de9929df4a993a" + ], + "linux_amd64": [ + "go1.25.0.linux-amd64.tar.gz", + "2852af0cb20a13139b3448992e69b868e50ed0f8a1e5940ee1de9e19a123b613" + ], + "linux_arm64": [ + "go1.25.0.linux-arm64.tar.gz", + "05de75d6994a2783699815ee553bd5a9327d8b79991de36e38b66862782f54ae" + ], + "linux_armv6l": [ + "go1.25.0.linux-armv6l.tar.gz", + "a5a8f8198fcf00e1e485b8ecef9ee020778bf32a408a4e8873371bfce458cd09" + ], + "linux_loong64": [ + "go1.25.0.linux-loong64.tar.gz", + "cab86b1cf761b1cb3bac86a8877cfc92e7b036fc0d3084123d77013d61432afc" + ], + "linux_mips": [ + "go1.25.0.linux-mips.tar.gz", + "d66b6fb74c3d91b9829dc95ec10ca1f047ef5e89332152f92e136cf0e2da5be1" + ], + "linux_mips64": [ + "go1.25.0.linux-mips64.tar.gz", + "4082e4381a8661bc2a839ff94ba3daf4f6cde20f8fb771b5b3d4762dc84198a2" + ], + "linux_mips64le": [ + "go1.25.0.linux-mips64le.tar.gz", + "70002c299ec7f7175ac2ef673b1b347eecfa54ae11f34416a6053c17f855afcc" + ], + "linux_mipsle": [ + "go1.25.0.linux-mipsle.tar.gz", + "b00a3a39eff099f6df9f1c7355bf28e4589d0586f42d7d4a394efb763d145a73" + ], + "linux_ppc64": [ + "go1.25.0.linux-ppc64.tar.gz", + "df166f33bd98160662560a72ff0b4ba731f969a80f088922bddcf566a88c1ec1" + ], + "linux_ppc64le": [ + "go1.25.0.linux-ppc64le.tar.gz", + "0f18a89e7576cf2c5fa0b487a1635d9bcbf843df5f110e9982c64df52a983ad0" + ], + "linux_riscv64": [ + "go1.25.0.linux-riscv64.tar.gz", + "c018ff74a2c48d55c8ca9b07c8e24163558ffec8bea08b326d6336905d956b67" + ], + "linux_s390x": [ + "go1.25.0.linux-s390x.tar.gz", + "34e5a2e19f2292fbaf8783e3a241e6e49689276aef6510a8060ea5ef54eee408" + ], + "netbsd_386": [ + "go1.25.0.netbsd-386.tar.gz", + "f8586cdb7aa855657609a5c5f6dbf523efa00c2bbd7c76d3936bec80aa6c0aba" + ], + "netbsd_amd64": [ + "go1.25.0.netbsd-amd64.tar.gz", + "ae8dc1469385b86a157a423bb56304ba45730de8a897615874f57dd096db2c2a" + ], + "netbsd_arm": [ + "go1.25.0.netbsd-arm.tar.gz", + "1ff7e4cc764425fc9dd6825eaee79d02b3c7cafffbb3691687c8d672ade76cb7" + ], + "netbsd_arm64": [ + "go1.25.0.netbsd-arm64.tar.gz", + "e1b310739f26724216aa6d7d7208c4031f9ff54c9b5b9a796ddc8bebcb4a5f16" + ], + "openbsd_386": [ + "go1.25.0.openbsd-386.tar.gz", + "4802a9b20e533da91adb84aab42e94aa56cfe3e5475d0550bed3385b182e69d8" + ], + "openbsd_amd64": [ + "go1.25.0.openbsd-amd64.tar.gz", + "c016cd984bebe317b19a4f297c4f50def120dc9788490540c89f28e42f1dabe1" + ], + "openbsd_arm": [ + "go1.25.0.openbsd-arm.tar.gz", + "a1e31d0bf22172ddde42edf5ec811ef81be43433df0948ece52fecb247ccfd8d" + ], + "openbsd_arm64": [ + "go1.25.0.openbsd-arm64.tar.gz", + "343ea8edd8c218196e15a859c6072d0dd3246fbbb168481ab665eb4c4140458d" + ], + "openbsd_ppc64": [ + "go1.25.0.openbsd-ppc64.tar.gz", + "694c14da1bcaeb5e3332d49bdc2b6d155067648f8fe1540c5de8f3cf8e157154" + ], + "openbsd_riscv64": [ + "go1.25.0.openbsd-riscv64.tar.gz", + "aa510ad25cf54c06cd9c70b6d80ded69cb20188ac6e1735655eef29ff7e7885f" + ], + "plan9_386": [ + "go1.25.0.plan9-386.tar.gz", + "46f8cef02086cf04bf186c5912776b56535178d4cb319cd19c9fdbdd29231986" + ], + "plan9_amd64": [ + "go1.25.0.plan9-amd64.tar.gz", + "29b34391d84095e44608a228f63f2f88113a37b74a79781353ec043dfbcb427b" + ], + "plan9_arm": [ + "go1.25.0.plan9-arm.tar.gz", + "0a047107d13ebe7943aaa6d54b1d7bbd2e45e68ce449b52915a818da715799c2" + ], + "solaris_amd64": [ + "go1.25.0.solaris-amd64.tar.gz", + "9977f9e4351984364a3b2b78f8b88bfd1d339812356d5237678514594b7d3611" + ], + "windows_386": [ + "go1.25.0.windows-386.zip", + "df9f39db82a803af0db639e3613a36681ab7a42866b1384b3f3a1045663961a7" + ], + "windows_amd64": [ + "go1.25.0.windows-amd64.zip", + "89efb4f9b30812eee083cc1770fdd2913c14d301064f6454851428f9707d190b" + ], + "windows_arm64": [ + "go1.25.0.windows-arm64.zip", + "27bab004c72b3d7bd05a69b6ec0fc54a309b4b78cc569dd963d8b3ec28bfdb8c" ] } } diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 00000000000..31e8ed9a8c6 --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,41 @@ +# Notices for Eclipse JGit + +This content is produced and maintained by the Eclipse JGit project. + +* Project home: https://projects.eclipse.org/projects/technology.jgit + +## Trademarks + +JGit™ is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Distribution License v1.0 which is available at +https://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: BSD-3-Clause + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-jgit/.github +* https://github.com/eclipse-jgit/jgit +* https://github.com/eclipse-jgit/jgit-pipelines +* https://github.com/eclipse-jgit/jgit-website + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. diff --git a/README.md b/README.md index acd12279b7e..c69aded4df5 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,15 @@ __org.eclipse.jgit.junit.ssh__: Helpers for unit testing - __org.eclipse.jgit.ssh.apache.test__: Unit tests for org.eclipse.jgit.ssh.apache - __org.eclipse.jgit.test__: Unit tests for org.eclipse.jgit +## SBOM + +To enhance supply chain security and offer users clear insight into project components, +Eclipse JGit now generates a Software Bill of Materials (SBOM) for every release. +These are published to the Eclipse Foundation SBOM registry +[Eclipse Foundation SBOM registry](https://sbom.eclipse.org/projects/e315d88f-0474-4a00-a6ed-0b95e62a2acc/collectionprojects), +with access instructions and usage details available in +this [documentation](https://eclipse-csi.github.io/security-handbook/sbom/registry.html). + ## Warnings/Caveats - Native symbolic links are supported, provided the file system supports diff --git a/WORKSPACE b/WORKSPACE deleted file mode 100644 index 6ba4a023827..00000000000 --- a/WORKSPACE +++ /dev/null @@ -1,2 +0,0 @@ -# This file marks the root of the Bazel workspace. -# See MODULE.bazel for external dependencies setup. diff --git a/lib/BUILD b/lib/BUILD index 20b85dafa17..833f2eaf859 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -59,6 +59,7 @@ java_library( visibility = [ "//org.eclipse.jgit.lfs:__pkg__", "//org.eclipse.jgit.lfs.server:__pkg__", + "//org.eclipse.jgit.lfs.server.ee8:__pkg__", ], exports = ["@external_deps//:com_google_code_gson_gson"], ) @@ -68,6 +69,7 @@ java_library( visibility = [ "//org.eclipse.jgit.http.apache:__pkg__", "//org.eclipse.jgit.lfs.server.test:__pkg__", + "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", ], exports = ["@external_deps//:org_apache_httpcomponents_httpclient"], @@ -78,8 +80,11 @@ java_library( visibility = [ "//org.eclipse.jgit.http.apache:__pkg__", "//org.eclipse.jgit.http.test:__pkg__", + "//org.eclipse.jgit.http.test.ee8:__pkg__", "//org.eclipse.jgit.lfs.server:__pkg__", + "//org.eclipse.jgit.lfs.server.ee8:__pkg__", "//org.eclipse.jgit.lfs.server.test:__pkg__", + "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", ], exports = ["@external_deps//:org_apache_httpcomponents_httpcore"], @@ -171,11 +176,40 @@ java_library( # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], exports = [ - "@external_deps//:org_eclipse_jetty_ee10_jetty_ee10_servlet", + "@external_deps//:org_eclipse_jetty_ee11_jetty_ee11_servlet", "@external_deps//:org_eclipse_jetty_jetty_util_ajax", ], ) +java_library( + name = "jetty-ee8-nested", + testonly = 1, + visibility = ["//org.eclipse.jgit.junit.http.ee8:__pkg__"], + exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_nested"], +) + +java_library( + name = "jetty-security-ee8", + testonly = 1, + visibility = [ + "//org.eclipse.jgit.http.test.ee8:__pkg__", + "//org.eclipse.jgit.junit.http.ee8:__pkg__", + "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__", + ], + exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_security"], +) + +java_library( + name = "jetty-servlet-ee8", + testonly = 1, + visibility = [ + "//org.eclipse.jgit.http.test.ee8:__pkg__", + "//org.eclipse.jgit.junit.http.ee8:__pkg__", + "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__", + ], + exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_servlet"], +) + java_library( name = "jetty-util", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. @@ -184,10 +218,10 @@ java_library( ) java_library( - name = "jetty-ee10-servlet", + name = "jetty-ee11-servlet", # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it. visibility = ["//visibility:public"], - exports = ["@external_deps//:org_eclipse_jetty_ee10_jetty_ee10_servlet"], + exports = ["@external_deps//:org_eclipse_jetty_ee11_jetty_ee11_servlet"], ) java_library( @@ -264,10 +298,10 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ - "@external_deps//:net_bytebuddy_byte_buddy_agent", + "@external_deps//:junit_junit", "@external_deps//:net_bytebuddy_byte_buddy", + "@external_deps//:net_bytebuddy_byte_buddy_agent", "@external_deps//:org_hamcrest_hamcrest", - "@external_deps//:junit_junit", "@external_deps//:org_mockito_mockito_core", "@external_deps//:org_objenesis_objenesis", ], @@ -278,8 +312,8 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ - "@external_deps//:net_bytebuddy_byte_buddy_agent", "@external_deps//:net_bytebuddy_byte_buddy", + "@external_deps//:net_bytebuddy_byte_buddy_agent", "@external_deps//:org_mockito_mockito_core", "@external_deps//:org_objenesis_objenesis", ], @@ -295,12 +329,13 @@ java_library( ) java_library( - name = "servlet-api", + name = "jakarta-servlet-api", visibility = [ "//org.eclipse.jgit.http.apache:__pkg__", "//org.eclipse.jgit.http.server:__pkg__", "//org.eclipse.jgit.http.test:__pkg__", "//org.eclipse.jgit.junit.http:__pkg__", + "//org.eclipse.jgit.junit.http.ee8:__pkg__", "//org.eclipse.jgit.lfs.server:__pkg__", "//org.eclipse.jgit.lfs.server.test:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", @@ -308,6 +343,18 @@ java_library( exports = ["@external_deps//:jakarta_servlet_jakarta_servlet_api_6_1_0"], ) +java_library( + name = "javax-servlet-api", + visibility = [ + "//org.eclipse.jgit.http.server.ee8:__pkg__", + "//org.eclipse.jgit.http.test.ee8:__pkg__", + "//org.eclipse.jgit.junit.http.ee8:__pkg__", + "//org.eclipse.jgit.lfs.server.ee8:__pkg__", + "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__", + ], + exports = ["@external_deps//:javax_servlet_javax_servlet_api"], +) + java_library( name = "slf4j-api", visibility = ["//visibility:public"], diff --git a/lib/jmh/BUILD b/lib/jmh/BUILD index 2b15300bfbc..e6d39770159 100644 --- a/lib/jmh/BUILD +++ b/lib/jmh/BUILD @@ -4,9 +4,9 @@ java_library( name = "jmh", visibility = ["//visibility:public"], exports = [ - "@external_deps//:org_openjdk_jmh_jmh_generator_annprocess", - "@external_deps//:org_openjdk_jmh_jmh_core", "@external_deps//:net_sf_jopt_simple_jopt_simple", "@external_deps//:org_apache_commons_commons_math3", + "@external_deps//:org_openjdk_jmh_jmh_core", + "@external_deps//:org_openjdk_jmh_jmh_generator_annprocess", ], ) diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index b114e7d36f4..29a2d3e84b5 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF @@ -5,14 +5,14 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git Import-Package: org.apache.tools.ant, - org.eclipse.jgit.ant.tasks;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.ant.tasks;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.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 483e833a83c..f9caf9430df 100644 --- a/org.eclipse.jgit.ant.test/pom.xml +++ b/org.eclipse.jgit.ant.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ant.test diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF index 18acf74202a..ce0918dd76c 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF @@ -3,14 +3,14 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ant Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git Import-Package: org.apache.tools.ant, - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)" + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)" Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.ant;version="7.6.0", - org.eclipse.jgit.ant.tasks;version="7.6.0"; +Export-Package: org.eclipse.jgit.ant;version="7.8.0", + org.eclipse.jgit.ant.tasks;version="7.8.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 d9b324140f9..b59816381bf 100644 --- a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.ant;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.ant;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index dab8a3d8e57..f08201344d8 100644 --- a/org.eclipse.jgit.ant/pom.xml +++ b/org.eclipse.jgit.ant/pom.xml @@ -15,7 +15,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ant diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF index 3f9d2c121af..6052ba70204 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -14,18 +14,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.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.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.6.0"; +Export-Package: org.eclipse.jgit.archive;version="7.8.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.6.0";x-internal:=true + org.eclipse.jgit.archive.internal;version="7.8.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 86336e3b9eb..41795216d4a 100644 --- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.archive;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.archive;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml index bbe279b4ccf..cd93dc089f4 100644 --- a/org.eclipse.jgit.archive/pom.xml +++ b/org.eclipse.jgit.archive/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.archive diff --git a/org.eclipse.jgit.benchmarks/BUILD b/org.eclipse.jgit.benchmarks/BUILD index 7c311e79946..91ceb7fe5f7 100644 --- a/org.eclipse.jgit.benchmarks/BUILD +++ b/org.eclipse.jgit.benchmarks/BUILD @@ -6,8 +6,8 @@ SRCS = glob( jmh_java_benchmarks( name = "benchmarks", - srcs = SRCS, testonly = 1, + srcs = SRCS, deps = [ "//lib:javaewah", "//lib:junit", diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml index b4daf7dc81c..0313e52f0c5 100644 --- a/org.eclipse.jgit.benchmarks/pom.xml +++ b/org.eclipse.jgit.benchmarks/pom.xml @@ -16,7 +16,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.benchmarks diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml index 80b421dac5f..6a12964f4f5 100644 --- a/org.eclipse.jgit.coverage/pom.xml +++ b/org.eclipse.jgit.coverage/pom.xml @@ -14,7 +14,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT 4.0.0 @@ -27,88 +27,88 @@ org.eclipse.jgit org.eclipse.jgit - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.ant - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.archive - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.http.apache - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.http.server - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.lfs - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.lfs.server - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.pgm - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.ui - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.ssh.apache - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.ant.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.http.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.pgm.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.lfs.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.lfs.server.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit org.eclipse.jgit.ssh.apache.test - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT 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 647c97d26e6..284f95c2801 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -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.6.0,7.7.0)", - org.eclipse.jgit.gpg.bc.internal.keys;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.sha1;version="[7.6.0,7.7.0)", +Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.85.0,2.0.0)", + org.bouncycastle.jce.provider;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.85.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.85.0,2.0.0)", + org.eclipse.jgit.gpg.bc.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.gpg.bc.internal.keys;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.sha1;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)", diff --git a/org.eclipse.jgit.gpg.bc.test/pom.xml b/org.eclipse.jgit.gpg.bc.test/pom.xml index 05e504ed732..b4e096442af 100644 --- a/org.eclipse.jgit.gpg.bc.test/pom.xml +++ b/org.eclipse.jgit.gpg.bc.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.gpg.bc.test diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF index cc6eda7801e..e0dd44b9074 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF @@ -3,29 +3,29 @@ 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.6.0,7.7.0)" +Fragment-Host: org.eclipse.jgit;bundle-version="[7.8.0,7.9.0)" Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/gpg_bc -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -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)", +Import-Package: org.bouncycastle.asn1;version="[1.85.0,2.0.0)", + org.bouncycastle.asn1.x9;version="[1.85.0,2.0.0)", + org.bouncycastle.bcpg;version="[1.85.0,2.0.0)", + org.bouncycastle.bcpg.sig;version="[1.85.0,2.0.0)", + org.bouncycastle.crypto.ec;version="[1.85.0,2.0.0)", + org.bouncycastle.gpg;version="[1.85.0,2.0.0)", + org.bouncycastle.gpg.keybox;version="[1.85.0,2.0.0)", + org.bouncycastle.gpg.keybox.jcajce;version="[1.85.0,2.0.0)", + org.bouncycastle.jcajce.interfaces;version="[1.85.0,2.0.0)", + org.bouncycastle.jcajce.util;version="[1.85.0,2.0.0)", + org.bouncycastle.math.ec;version="[1.85.0,2.0.0)", + org.bouncycastle.math.field;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp.jcajce;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.85.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.85.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.85.0,2.0.0)", org.slf4j;version="[1.7.0,3.0.0)" -Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.6.0";x-friends:="org.eclipse.jgit.gpg.bc.test", - org.eclipse.jgit.gpg.bc.internal.keys;version="7.6.0";x-friends:="org.eclipse.jgit.gpg.bc.test" +Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.8.0";x-friends:="org.eclipse.jgit.gpg.bc.test", + org.eclipse.jgit.gpg.bc.internal.keys;version="7.8.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 82df526a6e6..7dd65e27821 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.gpg.bc;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.gpg.bc/pom.xml b/org.eclipse.jgit.gpg.bc/pom.xml index bfc359047b3..74d9d1a9deb 100644 --- a/org.eclipse.jgit.gpg.bc/pom.xml +++ b/org.eclipse.jgit.gpg.bc/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.gpg.bc diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF index 9b0f12f83b6..30d22e1dfae 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git Bundle-Localization: OSGI-INF/l10n/plugin @@ -27,11 +27,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.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)" -Export-Package: org.eclipse.jgit.transport.http.apache;version="7.6.0"; + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)" +Export-Package: org.eclipse.jgit.transport.http.apache;version="7.8.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 cd65a4f2c40..9c108b338be 100644 --- a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml index 55828b2dbb8..5ae175baf3f 100644 --- a/org.eclipse.jgit.http.apache/pom.xml +++ b/org.eclipse.jgit.http.apache/pom.xml @@ -15,7 +15,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.http.apache diff --git a/org.eclipse.jgit.http.server.ee8/BUILD b/org.eclipse.jgit.http.server.ee8/BUILD new file mode 100644 index 00000000000..df39628ccad --- /dev/null +++ b/org.eclipse.jgit.http.server.ee8/BUILD @@ -0,0 +1,27 @@ +load("@rules_java//java:defs.bzl", "java_library") +load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar") + +package(default_visibility = ["//visibility:public"]) + +transform_srcjar( + name = "jgit-http-server-ee8-srcs", + direction = "to_javax", + sources = ["//org.eclipse.jgit.http.server:srcs"], + src_prefix = "org.eclipse.jgit.http.server/src/", +) + +filegroup( + name = "jgit-servlet-ee8-srcjar", + srcs = [":jgit-http-server-ee8-srcs"], +) + +java_library( + name = "jgit-servlet-ee8", + srcs = [":jgit-http-server-ee8-srcs"], + resource_strip_prefix = "org.eclipse.jgit.http.server/resources", + resources = ["//org.eclipse.jgit.http.server:jgit-servlet-resources"], + deps = [ + "//lib:javax-servlet-api", + "//org.eclipse.jgit:jgit", + ], +) diff --git a/org.eclipse.jgit.http.server/BUILD b/org.eclipse.jgit.http.server/BUILD index a0dae488b83..f6b4a1084fb 100644 --- a/org.eclipse.jgit.http.server/BUILD +++ b/org.eclipse.jgit.http.server/BUILD @@ -2,6 +2,15 @@ load("@rules_java//java:defs.bzl", "java_library") package(default_visibility = ["//visibility:public"]) +filegroup( + name = "srcs", + srcs = glob(["src/**/*.java"]), + visibility = [ + "//org.eclipse.jgit.http.server.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) + filegroup( name = "jgit-servlet-resources", srcs = glob(["resources/**"]), @@ -9,11 +18,11 @@ filegroup( java_library( name = "jgit-servlet", - srcs = glob(["src/**/*.java"]), + srcs = [":srcs"], resource_strip_prefix = "org.eclipse.jgit.http.server/resources", resources = [":jgit-servlet-resources"], deps = [ - "//lib:servlet-api", + "//lib:jakarta-servlet-api", # We want these deps to be provided_deps "//org.eclipse.jgit:jgit", ], diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index e97e314c22c..cac9050e685 100644 --- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF @@ -3,31 +3,31 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Export-Package: org.eclipse.jgit.http.server;version="7.6.0", - org.eclipse.jgit.http.server.glue;version="7.6.0"; +Export-Package: org.eclipse.jgit.http.server;version="7.8.0", + org.eclipse.jgit.http.server.glue;version="7.8.0"; uses:="jakarta.servlet, jakarta.servlet.http", - org.eclipse.jgit.http.server.resolver;version="7.6.0"; + org.eclipse.jgit.http.server.resolver;version="7.8.0"; uses:="jakarta.servlet.http org.eclipse.jgit.transport.resolver, org.eclipse.jgit.lib, org.eclipse.jgit.transport, -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.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.parser;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.resolver;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)" +Import-Package: jakarta.servlet;version="[6.1.0,7.0.0)", + jakarta.servlet.http;version="[6.1.0,7.0.0)", + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.parser;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.resolver;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.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 3d4256867e2..6bb08e3336d 100644 --- a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index 2be8efe1a96..f9e847baab7 100644 --- a/org.eclipse.jgit.http.server/pom.xml +++ b/org.eclipse.jgit.http.server/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.http.server diff --git a/org.eclipse.jgit.http.test.ee8/BUILD b/org.eclipse.jgit.http.test.ee8/BUILD new file mode 100644 index 00000000000..a6a5506e988 --- /dev/null +++ b/org.eclipse.jgit.http.test.ee8/BUILD @@ -0,0 +1,84 @@ +load("@rules_java//java:defs.bzl", "java_library") +load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests") +load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar") + +transform_srcjar( + name = "helpers-srcs", + testonly = 1, + direction = "to_javax", + sources = ["//org.eclipse.jgit.http.test:helper-srcs"], + src_prefix = "org.eclipse.jgit.http.test/src/", + visibility = ["//tools/jgit-ee8:__pkg__"], +) + +transform_srcjar( + name = "test-srcs", + testonly = 1, + direction = "to_javax", + sources = ["//org.eclipse.jgit.http.test:test-srcs"], + src_prefix = "org.eclipse.jgit.http.test/tst/", + visibility = ["//tools/jgit-ee8:__pkg__"], +) + +transform_srcjar( + name = "server-unit-test-srcs", + testonly = 1, + direction = "to_javax", + sources = ["//org.eclipse.jgit.http.test:http-server-unit-test-srcs"], + src_prefix = "org.eclipse.jgit.http.test/tst/", +) + +# Fast slice for the server utility tests; the default EE8 suite runs the full +# HTTP test target, which already includes these classes. +junit_tests( + name = "server_unit", + suite_srcs = ["//org.eclipse.jgit.http.test:http-server-unit-test-srcs"], + tags = ["http"], + srcs = [":server-unit-test-srcs"], + deps = [ + "//lib:junit", + "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.junit:junit", + ], +) + +junit_tests( + name = "http", + suite_srcs = ["//org.eclipse.jgit.http.test:test-srcs"], + tags = ["http"], + srcs = [":test-srcs"], + deps = [ + ":helpers", + "//lib:commons-logging", + "//lib:httpcore", + "//lib:javax-servlet-api", + "//lib:jetty-http", + "//lib:jetty-io", + "//lib:jetty-security", + "//lib:jetty-security-ee8", + "//lib:jetty-server", + "//lib:jetty-servlet-ee8", + "//lib:jetty-util", + "//lib:junit", + "//lib:slf4j-api", + "//lib:slf4j-simple", + "//org.eclipse.jgit.http.apache:http-apache", + "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.junit.http.ee8:junit-http-ee8", + "//org.eclipse.jgit.junit:junit", + ], +) + +java_library( + name = "helpers", + testonly = 1, + srcs = [":helpers-srcs"], + deps = [ + "//lib:javax-servlet-api", + "//lib:junit", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.junit:junit", + ], +) diff --git a/org.eclipse.jgit.http.test/BUILD b/org.eclipse.jgit.http.test/BUILD index 732b4fae2c1..cb6a738178a 100644 --- a/org.eclipse.jgit.http.test/BUILD +++ b/org.eclipse.jgit.http.test/BUILD @@ -4,14 +4,52 @@ load( ) load("@rules_java//java:defs.bzl", "java_library") +HTTP_HELPER_SRCS = glob(["src/**/*.java"]) + +HTTP_TEST_SRCS = glob(["tst/**/*.java"]) + +HTTP_SERVER_UNIT_TEST_SRCS = [ + "tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java", + "tst/org/eclipse/jgit/http/server/RootLocaleTest.java", + "tst/org/eclipse/jgit/http/server/ServletUtilsTest.java", +] + +filegroup( + name = "helper-srcs", + testonly = 1, + srcs = HTTP_HELPER_SRCS, + visibility = [ + "//org.eclipse.jgit.http.test.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) + +filegroup( + name = "test-srcs", + testonly = 1, + srcs = HTTP_TEST_SRCS, + visibility = [ + "//org.eclipse.jgit.http.test.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) + +filegroup( + name = "http-server-unit-test-srcs", + testonly = 1, + srcs = HTTP_SERVER_UNIT_TEST_SRCS, + visibility = ["//org.eclipse.jgit.http.test.ee8:__pkg__"], +) + junit_tests( name = "http", - srcs = glob(["tst/**/*.java"]), + srcs = HTTP_TEST_SRCS, tags = ["http"], deps = [ ":helpers", "//lib:commons-logging", "//lib:httpcore", + "//lib:jakarta-servlet-api", "//lib:jetty-http", "//lib:jetty-io", "//lib:jetty-security", @@ -19,7 +57,6 @@ junit_tests( "//lib:jetty-servlet", "//lib:jetty-util", "//lib:junit", - "//lib:servlet-api", "//lib:slf4j-api", "//lib:slf4j-simple", "//org.eclipse.jgit.http.apache:http-apache", @@ -33,10 +70,10 @@ junit_tests( java_library( name = "helpers", testonly = 1, - srcs = glob(["src/**/*.java"]), + srcs = HTTP_HELPER_SRCS, deps = [ + "//lib:jakarta-servlet-api", "//lib:junit", - "//lib:servlet-api", "//org.eclipse.jgit:jgit", "//org.eclipse.jgit.junit:junit", ], diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index dd507d323f5..aa39fe4db4d 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF @@ -3,13 +3,13 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", - jakarta.servlet.http;version="[6.0.0,7.0.0)", +Import-Package: jakarta.servlet;version="[6.1.0,7.0.0)", + jakarta.servlet.http;version="[6.1.0,7.0.0)", net.bytebuddy.agent;version="[1.9.0,2.0.0)", net.bytebuddy.dynamic.loading;version="[1.9.0,2.0.0)", org.apache.commons.codec;version="[1.6.0,2.0.0)", @@ -17,7 +17,7 @@ Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", org.apache.http;version="[4.3.0,5.0.0)", org.apache.http.client;version="[4.4.0,5.0.0)", org.apache.http.message;version="[4.3.0,5.0.0)", - org.eclipse.jetty.ee10.servlet;version="[12.0.0,13.0.0)", + org.eclipse.jetty.ee11.servlet;version="[12.0.0,13.0.0)", org.eclipse.jetty.http;version="[12.0.0,13.0.0)", org.eclipse.jetty.io;version="[12.0.0,13.0.0)", org.eclipse.jetty.security;version="[12.0.0,13.0.0)", @@ -28,26 +28,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.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.http.server;version="[7.6.0,7.7.0)", - org.eclipse.jgit.http.server.glue;version="[7.6.0,7.7.0)", - org.eclipse.jgit.http.server.resolver;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http.apache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.resolver;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.http.server;version="[7.8.0,7.9.0)", + org.eclipse.jgit.http.server.glue;version="[7.8.0,7.9.0)", + org.eclipse.jgit.http.server.resolver;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http.apache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.resolver;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.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.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml index c8d9baac5b2..9f4f49b0ffb 100644 --- a/org.eclipse.jgit.http.test/pom.xml +++ b/org.eclipse.jgit.http.test/pom.xml @@ -18,7 +18,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.http.test @@ -82,8 +82,8 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet + org.eclipse.jetty.ee11 + jetty-ee11-servlet diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java index fd78ba888ca..dfc6660032e 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AdvertiseErrorTest.java @@ -17,8 +17,8 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.RemoteRepositoryException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.http.server.GitServlet; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java index 7ccc0e5d9af..2d78f81297c 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java @@ -25,9 +25,9 @@ import java.util.List; import java.util.Map; -import org.eclipse.jetty.ee10.servlet.DefaultServlet; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.DefaultServlet; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.NotSupportedException; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.http.AccessEvent; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java index 9b9f6843dee..b38c7545a98 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java @@ -25,8 +25,8 @@ import java.util.List; import java.util.Map; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.NotSupportedException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.junit.TestRepository; @@ -140,7 +140,14 @@ public void testListRemote() throws IOException { assertEquals(join(remoteURI, "HEAD"), head.getPath()); assertEquals(0, head.getParameters().size()); assertEquals(200, head.getStatus()); - assertEquals("text/plain", head.getResponseHeader(HDR_CONTENT_TYPE)); + assertEquals("text/plain", + mediaType(head.getResponseHeader(HDR_CONTENT_TYPE))); + } + + private static String mediaType(String contentType) { + int parameterStart = contentType.indexOf(';'); + return parameterStart >= 0 ? contentType.substring(0, parameterStart) + : contentType; } @Test diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ErrorServletTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ErrorServletTest.java index 9a610c6b738..b78451e0a2e 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ErrorServletTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ErrorServletTest.java @@ -15,8 +15,8 @@ import java.net.HttpURLConnection; import java.net.URI; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.http.server.glue.ErrorServlet; import org.eclipse.jgit.junit.http.AppServer; import org.junit.After; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletInitTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletInitTest.java index c8873606f33..6f9e99f460d 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletInitTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletInitTest.java @@ -13,8 +13,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.junit.http.AppServer; import org.eclipse.jgit.junit.http.MockServletConfig; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java index 9331efa6030..b3fa32d26d4 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java @@ -17,8 +17,8 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.TooLargePackException; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java index 082d853f42d..af4a2ea9578 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java @@ -22,8 +22,8 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java index 3937627f53c..9ee91af53f1 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java @@ -30,9 +30,9 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.DefaultServlet; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.DefaultServlet; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.errors.NoRemoteRepositoryException; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -41,7 +41,7 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.http.AccessEvent; -import org.eclipse.jgit.junit.http.AppServer; +import org.eclipse.jgit.junit.http.AppServerBase; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; @@ -266,12 +266,12 @@ public void testListRemote_Dumb_Auth() throws Exception { Repository dst = createBareRepository(); try (Transport t = Transport.open(dst, dumbAuthBasicURI)) { t.setCredentialsProvider(new UsernamePasswordCredentialsProvider( - AppServer.username, AppServer.password)); + AppServerBase.username, AppServerBase.password)); t.openFetch().close(); } try (Transport t = Transport.open(dst, dumbAuthBasicURI)) { t.setCredentialsProvider(new UsernamePasswordCredentialsProvider( - AppServer.username, "")); + AppServerBase.username, "")); try { t.openFetch(); fail("connection opened even info/refs needs auth basic and we provide wrong password"); diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java index 183043b2d42..9165cfe30d2 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java @@ -16,8 +16,8 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java index 74028d762d5..36865018a18 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ProtocolErrorTest.java @@ -22,8 +22,8 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.http.server.GitSmartHttpTools; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/RegexPipelineTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/RegexPipelineTest.java index dfdb975ef61..ee75997fb59 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/RegexPipelineTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/RegexPipelineTest.java @@ -59,8 +59,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.http.server.glue.MetaServlet; import org.eclipse.jgit.http.server.glue.RegexGroupFilter; import org.eclipse.jgit.junit.http.AppServer; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java index d5694316845..0cd019133aa 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SetAdditionalHeadersTest.java @@ -20,9 +20,9 @@ import java.util.List; import java.util.Map; -import org.eclipse.jetty.ee10.servlet.DefaultServlet; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.DefaultServlet; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.http.AccessEvent; import org.eclipse.jgit.lib.Repository; diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java index 13ed36cb8c4..b1857d6e382 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerSslTest.java @@ -29,9 +29,9 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.ee10.servlet.FilterHolder; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.FilterHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.errors.UnsupportedCredentialItem; import org.eclipse.jgit.http.server.GitServlet; 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 b0d17adb3a0..84b9fe6e1e0 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 @@ -52,9 +52,9 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.ee10.servlet.FilterHolder; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.FilterHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.TransportConfigCallback; import org.eclipse.jgit.errors.NoRemoteRepositoryException; @@ -68,6 +68,7 @@ import org.eclipse.jgit.junit.TestRng; import org.eclipse.jgit.junit.http.AccessEvent; import org.eclipse.jgit.junit.http.AppServer; +import org.eclipse.jgit.junit.http.AppServerBase; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; @@ -111,7 +112,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { private Repository remoteRepository; private CredentialsProvider testCredentials = new UsernamePasswordCredentialsProvider( - AppServer.username, AppServer.password); + AppServerBase.username, AppServerBase.password); private URIish remoteURI; @@ -998,7 +999,7 @@ public void testInitialClone_WithPreAuthentication() throws Exception { Transport t = Transport.open(dst, authURI)) { assertFalse(dst.getObjectDatabase().has(A_txt)); ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password); + AppServerBase.username, AppServerBase.password); t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); assertTrue(dst.getObjectDatabase().has(A_txt)); assertEquals(B, dst.exactRef(master).getObjectId()); @@ -1018,7 +1019,7 @@ public void testInitialClone_WithPreAuthenticationCleared() Transport t = Transport.open(dst, authURI)) { assertFalse(dst.getObjectDatabase().has(A_txt)); ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password); + AppServerBase.username, AppServerBase.password); ((TransportHttp) t).setPreemptiveBasicAuthentication(null, null); t.setCredentialsProvider(testCredentials); t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); @@ -1043,7 +1044,7 @@ public void testInitialClone_PreAuthenticationTooLate() throws Exception { Transport t = Transport.open(dst, authURI)) { assertFalse(dst.getObjectDatabase().has(A_txt)); ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password); + AppServerBase.username, AppServerBase.password); t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); assertTrue(dst.getObjectDatabase().has(A_txt)); assertEquals(B, dst.exactRef(master).getObjectId()); @@ -1053,7 +1054,7 @@ public void testInitialClone_PreAuthenticationTooLate() throws Exception { assertFetchRequests(requests, 0); assertThrows(IllegalStateException.class, () -> ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password)); + AppServerBase.username, AppServerBase.password)); assertThrows(IllegalStateException.class, () -> ((TransportHttp) t) .setPreemptiveBasicAuthentication(null, null)); } @@ -1066,7 +1067,7 @@ public void testInitialClone_WithWrongPreAuthenticationAndCredentialProvider() Transport t = Transport.open(dst, authURI)) { assertFalse(dst.getObjectDatabase().has(A_txt)); ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password + 'x'); + AppServerBase.username, AppServerBase.password + 'x'); t.setCredentialsProvider(testCredentials); t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); assertTrue(dst.getObjectDatabase().has(A_txt)); @@ -1090,7 +1091,7 @@ public void testInitialClone_WithWrongPreAuthentication() throws Exception { Transport t = Transport.open(dst, authURI)) { assertFalse(dst.getObjectDatabase().has(A_txt)); ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password + 'x'); + AppServerBase.username, AppServerBase.password + 'x'); TransportException e = assertThrows(TransportException.class, () -> t.fetch(NullProgressMonitor.INSTANCE, mirror(master))); @@ -1108,8 +1109,8 @@ public void testInitialClone_WithWrongPreAuthentication() throws Exception { @Test public void testInitialClone_WithUserInfo() throws Exception { - URIish withUserInfo = authURI.setUser(AppServer.username) - .setPass(AppServer.password); + URIish withUserInfo = authURI.setUser(AppServerBase.username) + .setPass(AppServerBase.password); try (Repository dst = createBareRepository(); Transport t = Transport.open(dst, withUserInfo)) { assertFalse(dst.getObjectDatabase().has(A_txt)); @@ -1127,13 +1128,13 @@ public void testInitialClone_WithUserInfo() throws Exception { @Test public void testInitialClone_PreAuthOverridesUserInfo() throws Exception { - URIish withUserInfo = authURI.setUser(AppServer.username) - .setPass(AppServer.password + 'x'); + URIish withUserInfo = authURI.setUser(AppServerBase.username) + .setPass(AppServerBase.password + 'x'); try (Repository dst = createBareRepository(); Transport t = Transport.open(dst, withUserInfo)) { assertFalse(dst.getObjectDatabase().has(A_txt)); ((TransportHttp) t).setPreemptiveBasicAuthentication( - AppServer.username, AppServer.password); + AppServerBase.username, AppServerBase.password); t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); assertTrue(dst.getObjectDatabase().has(A_txt)); assertEquals(B, dst.exactRef(master).getObjectId()); @@ -1174,7 +1175,7 @@ public void testInitialClone_WithAuthenticationWrongCredentials() Transport t = Transport.open(dst, authURI)) { assertFalse(dst.getObjectDatabase().has(A_txt)); t.setCredentialsProvider(new UsernamePasswordCredentialsProvider( - AppServer.username, "wrongpassword")); + AppServerBase.username, "wrongpassword")); t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); fail("Should not have succeeded -- wrong password"); } catch (TransportException e) { diff --git a/org.eclipse.jgit.junit.http.ee8/BUILD b/org.eclipse.jgit.junit.http.ee8/BUILD new file mode 100644 index 00000000000..c7f6fb5a537 --- /dev/null +++ b/org.eclipse.jgit.junit.http.ee8/BUILD @@ -0,0 +1,43 @@ +load("@rules_java//java:defs.bzl", "java_library") + +package(default_visibility = ["//visibility:public"]) + +java_library( + name = "junit-http-ee8", + testonly = 1, + srcs = [ + "//org.eclipse.jgit.junit.http:junit-http-ee8-srcs", + # AppServer diverges from the canonical Jakarta version and is copied + # from the servlet-4 branch as a hand-maintained EE8 overlay. + "src/org/eclipse/jgit/junit/http/AppServer.java", + ], + resources = glob( + ["resources/**"], + allow_empty = True, + ), + deps = [ + "//lib:javax-servlet-api", + "//lib:jetty-ee8-nested", + "//lib:jetty-http", + "//lib:jetty-io", + "//lib:jetty-security", + "//lib:jetty-security-ee8", + "//lib:jetty-server", + "//lib:jetty-servlet-ee8", + "//lib:jetty-session", + "//lib:jetty-util", + "//lib:junit", + "//lib:slf4j-api", + "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.junit:junit", + ], +) + +test_suite( + name = "tests", + tests = [ + "//org.eclipse.jgit.http.test.ee8:http", + "//org.eclipse.jgit.lfs.server.test.ee8:lfs_server", + ], +) diff --git a/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java new file mode 100644 index 00000000000..3627d920a89 --- /dev/null +++ b/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010, 2017 Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.junit.http; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.eclipse.jetty.ee8.nested.ServletConstraint; +import org.eclipse.jetty.ee8.security.ConstraintMapping; +import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler; +import org.eclipse.jetty.ee8.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.ee8.servlet.ServletContextHandler; +import org.eclipse.jetty.security.AbstractLoginService; + +/** + * Tiny web application server for unit testing, wired for the EE8 + * (javax.servlet / Jetty EE8) generation. + *

+ * Only the Jetty security wiring is generation specific; everything else is + * inherited from the generated {@link AppServerBase}. This is the hand + * maintained EE8 overlay that the canonical {@code AppServer} cannot be + * rewritten into automatically, because the Jetty EE8 security API + * ({@code ServletConstraint} + {@code setSecurityHandler}) differs structurally + * from the EE10 one. + */ +public class AppServer extends AppServerBase { + /** + * Constructor for AppServer. + */ + public AppServer() { + super(); + } + + /** + * Constructor for AppServer. + * + * @param port + * the http port number; may be zero to allocate a port + * dynamically + * @since 4.2 + */ + public AppServer(int port) { + super(port); + } + + /** + * Constructor for AppServer. + * + * @param port + * for http, may be zero to allocate a port dynamically + * @param sslPort + * for https,may be zero to allocate a port dynamically. If + * negative, the server will be set up without https support. + * @since 4.9 + */ + public AppServer(int port, int sslPort) { + super(port, sslPort); + } + + private ConstraintMapping createConstraintMapping() { + ConstraintMapping cm = new ConstraintMapping(); + cm.setConstraint(new ServletConstraint()); + cm.getConstraint().setAuthenticate(true); + cm.getConstraint().setDataConstraint(ServletConstraint.DC_NONE); + cm.getConstraint().setRoles(new String[] { authRole }); + return cm; + } + + @Override + protected void configureAuthentication(ServletContextHandler ctx, + String[] methods) { + AbstractLoginService users = new TestMappedLoginService(authRole); + List mappings = new ArrayList<>(); + if (methods == null || methods.length == 0) { + ConstraintMapping cm = createConstraintMapping(); + cm.setPathSpec("/*"); + mappings.add(cm); + } else { + for (String method : methods) { + ConstraintMapping cm = createConstraintMapping(); + cm.setMethod(method.toUpperCase(Locale.ROOT)); + cm.setPathSpec("/*"); + mappings.add(cm); + } + } + + ConstraintSecurityHandler sec = new ConstraintSecurityHandler(); + sec.setRealmName(realm); + sec.setAuthenticator(new BasicAuthenticator()); + sec.setLoginService(users); + sec.setConstraintMappings(mappings.toArray(new ConstraintMapping[0])); + ctx.setSecurityHandler(sec); + } +} diff --git a/org.eclipse.jgit.junit.http/.settings/.api_filters b/org.eclipse.jgit.junit.http/.settings/.api_filters new file mode 100644 index 00000000000..1736f52f9f2 --- /dev/null +++ b/org.eclipse.jgit.junit.http/.settings/.api_filters @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.jgit.junit.http/BUILD b/org.eclipse.jgit.junit.http/BUILD index 66620cea510..8ab98ac5d95 100644 --- a/org.eclipse.jgit.junit.http/BUILD +++ b/org.eclipse.jgit.junit.http/BUILD @@ -1,14 +1,43 @@ load("@rules_java//java:defs.bzl", "java_library") +load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar") package(default_visibility = ["//visibility:public"]) +JUNIT_HTTP_SRCS = glob(["src/**/*.java"]) + +JUNIT_HTTP_EE8_TRANSFORM_SRCS = glob( + ["src/**/*.java"], + exclude = ["src/org/eclipse/jgit/junit/http/AppServer.java"], +) + +filegroup( + name = "srcs", + testonly = 1, + srcs = JUNIT_HTTP_SRCS, + visibility = [ + "//org.eclipse.jgit.junit.http.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) + +filegroup( + name = "ee8-transform-srcs", + testonly = 1, + srcs = JUNIT_HTTP_EE8_TRANSFORM_SRCS, + visibility = ["//tools/jgit-ee8:__pkg__"], +) + java_library( name = "junit-http", testonly = 1, - srcs = glob(["src/**/*.java"]), - resources = glob(["resources/**"], allow_empty=True), + srcs = JUNIT_HTTP_SRCS, + resources = glob( + ["resources/**"], + allow_empty = True, + ), # TODO(davido): we want here provided deps deps = [ + "//lib:jakarta-servlet-api", "//lib:jetty-http", "//lib:jetty-io", "//lib:jetty-security", @@ -17,10 +46,20 @@ java_library( "//lib:jetty-session", "//lib:jetty-util", "//lib:junit", - "//lib:servlet-api", "//lib:slf4j-api", "//org.eclipse.jgit.http.server:jgit-servlet", "//org.eclipse.jgit:jgit", "//org.eclipse.jgit.junit:junit", ], ) + +transform_srcjar( + name = "junit-http-ee8-srcs", + direction = "to_javax", + sources = JUNIT_HTTP_EE8_TRANSFORM_SRCS, + src_prefix = "org.eclipse.jgit.junit.http/src/", + visibility = [ + "//org.eclipse.jgit.junit.http.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index 03aae759347..0de8b2edbef 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF @@ -3,17 +3,17 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", - jakarta.servlet.http;version="[6.0.0,7.0.0)", +Import-Package: jakarta.servlet;version="[6.1.0,7.0.0)", + jakarta.servlet.http;version="[6.1.0,7.0.0)", org.apache.commons.logging;version="[1.1.1,2.0.0)", - org.eclipse.jetty.ee10.servlet;version="[12.0.0,13.0.0)", - org.eclipse.jetty.ee10.servlet.security;version="[12.0.0,13.0.0)", + org.eclipse.jetty.ee11.servlet;version="[12.0.0,13.0.0)", + org.eclipse.jetty.ee11.servlet.security;version="[12.0.0,13.0.0)", org.eclipse.jetty.http;version="[12.0.0,13.0.0)", org.eclipse.jetty.security;version="[12.0.0,13.0.0)", org.eclipse.jetty.security.authentication;version="[12.0.0,13.0.0)", @@ -23,17 +23,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.6.0,7.7.0)", - org.eclipse.jgit.http.server;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.resolver;version="[7.6.0,7.7.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.http.server;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.resolver;version="[7.8.0,7.9.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.6.0"; +Export-Package: org.eclipse.jgit.junit.http;version="7.8.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 64d2e4eb2bb..45634067f51 100644 --- a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index c5a9e8e2648..951ef3e083c 100644 --- a/org.eclipse.jgit.junit.http/pom.xml +++ b/org.eclipse.jgit.junit.http/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.junit.http @@ -58,8 +58,8 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet + org.eclipse.jetty.ee11 + jetty-ee11-servlet diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java index 76e437bc3d6..710442e2baf 100644 --- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java @@ -10,95 +10,30 @@ package org.eclipse.jgit.junit.http; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.nio.file.Files; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping; -import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.security.ConstraintMapping; +import org.eclipse.jetty.ee11.servlet.security.ConstraintSecurityHandler; import org.eclipse.jetty.security.AbstractLoginService; -import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.Constraint; -import org.eclipse.jetty.security.RolePrincipal; -import org.eclipse.jetty.security.UserPrincipal; import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.util.security.Password; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jgit.transport.URIish; /** - * Tiny web application server for unit testing. + * Tiny web application server for unit testing, wired for the Jakarta servlet + * (Jetty EE10) generation. *

- * Tests should start the server in their {@code setUp()} method and stop the - * server in their {@code tearDown()} method. Only while started the server's - * URL and/or port number can be obtained. + * Only the Jetty security wiring is generation specific; everything else lives + * in {@link AppServerBase}. */ -public class AppServer { - /** Realm name for the secure access areas. */ - public static final String realm = "Secure Area"; - - /** Username for secured access areas. */ - public static final String username = "agitter"; - - /** Password for {@link #username} in secured access areas. */ - public static final String password = "letmein"; - - /** SSL keystore password; must have at least 6 characters. */ - private static final String keyPassword = "mykeys"; - - /** Role for authentication. */ - private static final String authRole = "can-access"; - - static { - // Install a logger that throws warning messages. - // - final String prop = "org.eclipse.jetty.util.log.class"; - System.setProperty(prop, RecordingLogger.class.getName()); - } - - private final Server server; - - private final HttpConfiguration config; - - private final ServerConnector connector; - - private final HttpConfiguration secureConfig; - - private final ServerConnector secureConnector; - - private final ContextHandlerCollection contexts; - - private final TestRequestLog log; - - private List filesToDelete = new ArrayList<>(); - +public class AppServer extends AppServerBase { /** * Constructor for AppServer. */ public AppServer() { - this(0, -1); + super(); } /** @@ -110,7 +45,7 @@ public AppServer() { * @since 4.2 */ public AppServer(int port) { - this(port, -1); + super(port); } /** @@ -124,185 +59,7 @@ public AppServer(int port) { * @since 4.9 */ public AppServer(int port, int sslPort) { - server = new Server(); - - config = new HttpConfiguration(); - config.setSecureScheme("https"); - config.setSecurePort(0); - config.setOutputBufferSize(32768); - - connector = new ServerConnector(server, - new HttpConnectionFactory(config)); - connector.setPort(port); - String ip; - String hostName; - try { - final InetAddress me = InetAddress.getByName("localhost"); - ip = me.getHostAddress(); - connector.setHost(ip); - hostName = InetAddress.getLocalHost().getCanonicalHostName(); - } catch (UnknownHostException e) { - throw new RuntimeException("Cannot find localhost", e); - } - - if (sslPort >= 0) { - SslContextFactory.Server sslContextFactory = createTestSslContextFactory( - hostName, ip); - secureConfig = new HttpConfiguration(config); - secureConfig.addCustomizer(new SecureRequestCustomizer()); - HttpConnectionFactory http11 = new HttpConnectionFactory( - secureConfig); - SslConnectionFactory tls = new SslConnectionFactory( - sslContextFactory, http11.getProtocol()); - secureConnector = new ServerConnector(server, tls, http11); - secureConnector.setPort(sslPort); - secureConnector.setHost(ip); - } else { - secureConfig = null; - secureConnector = null; - } - - contexts = new ContextHandlerCollection(); - - log = new TestRequestLog(); - log.setHandler(contexts); - - if (secureConnector == null) { - server.setConnectors(new Connector[] { connector }); - } else { - server.setConnectors( - new Connector[] { connector, secureConnector }); - } - server.setHandler(log); - } - - private SslContextFactory.Server createTestSslContextFactory( - String hostName, String ip) { - SslContextFactory.Server factory = new SslContextFactory.Server(); - - String dName = "CN=localhost,OU=JGit,O=Eclipse,ST=Ontario,L=Toronto,C=CA"; - - try { - File tmpDir = Files.createTempDirectory("jks").toFile(); - tmpDir.deleteOnExit(); - makePrivate(tmpDir); - File keyStore = new File(tmpDir, "keystore.jks"); - File keytool = new File( - new File(new File(System.getProperty("java.home")), "bin"), - "keytool"); - Runtime.getRuntime().exec( - new String[] { - keytool.getAbsolutePath(), // - "-keystore", keyStore.getAbsolutePath(), // - "-storepass", keyPassword, - "-alias", hostName, // - "-ext", "bc=ca:true", // - "-ext", - String.format( - "san=ip:%s,ip:127.0.0.1,ip:[::1],DNS:%s", - ip, hostName), // - "-genkeypair", // - "-keyalg", "RSA", // - "-keypass", keyPassword, // - "-dname", dName, // - "-validity", "2" // - }).waitFor(); - keyStore.deleteOnExit(); - makePrivate(keyStore); - filesToDelete.add(keyStore); - filesToDelete.add(tmpDir); - factory.setKeyStorePath(keyStore.getAbsolutePath()); - factory.setKeyStorePassword(keyPassword); - factory.setKeyManagerPassword(keyPassword); - factory.setTrustStorePath(keyStore.getAbsolutePath()); - factory.setTrustStorePassword(keyPassword); - } catch (InterruptedException | IOException e) { - throw new RuntimeException("Cannot create ssl key/certificate", e); - } - return factory; - } - - private void makePrivate(File file) { - file.setReadable(false); - file.setWritable(false); - file.setExecutable(false); - file.setReadable(true, true); - file.setWritable(true, true); - if (file.isDirectory()) { - file.setExecutable(true, true); - } - } - - /** - * Create a new servlet context within the server. - *

- * This method should be invoked before the server is started, once for each - * context the caller wants to register. - * - * @param path - * path of the context; use "/" for the root context if binding - * to the root is desired. - * @return the context to add servlets into. - * @since 7.0 - */ - public ServletContextHandler addContext(String path) { - assertNotYetSetUp(); - if ("".equals(path)) - path = "/"; - - ServletContextHandler ctx = new ServletContextHandler(); - ctx.setContextPath(path); - contexts.addHandler(ctx); - - return ctx; - } - - /** - * Configure basic authentication. - * - * @param ctx - * servlet context handler - * @param methods - * the methods - * @return servlet context handler - * @since 7.0 - */ - public ServletContextHandler authBasic(ServletContextHandler ctx, - String... methods) { - assertNotYetSetUp(); - auth(ctx, new BasicAuthenticator(), methods); - return ctx; - } - - static class TestMappedLoginService extends AbstractLoginService { - private RolePrincipal role; - - protected final Map users = new ConcurrentHashMap<>(); - - TestMappedLoginService(String role) { - this.role = new RolePrincipal(role); - } - - @Override - protected void doStart() throws Exception { - UserPrincipal p = new UserPrincipal(username, - new Password(password)); - users.put(username, p); - super.doStart(); - } - - @Override - protected UserPrincipal loadUserInfo(String user) { - return users.get(user); - } - - @Override - protected List loadRoleInfo(UserPrincipal user) { - if (users.get(user.getName()) == null) { - return null; - } - return Collections.singletonList(role); - } + super(port, sslPort); } private ConstraintMapping createConstraintMapping() { @@ -315,8 +72,9 @@ private ConstraintMapping createConstraintMapping() { return cm; } - private void auth(ServletContextHandler ctx, Authenticator authType, - String... methods) { + @Override + protected void configureAuthentication(ServletContextHandler ctx, + String[] methods) { AbstractLoginService users = new TestMappedLoginService(authRole); List mappings = new ArrayList<>(); if (methods == null || methods.length == 0) { @@ -331,133 +89,12 @@ private void auth(ServletContextHandler ctx, Authenticator authType, ConstraintSecurityHandler sec = new ConstraintSecurityHandler(); sec.setRealmName(realm); - sec.setAuthenticator(authType); + sec.setAuthenticator(new BasicAuthenticator()); sec.setLoginService(users); - sec.setConstraintMappings( - mappings.toArray(new ConstraintMapping[0])); + sec.setConstraintMappings(mappings.toArray(new ConstraintMapping[0])); sec.setHandler(ctx); contexts.removeHandler(ctx); contexts.addHandler(sec); } - - /** - * Start the server on a random local port. - * - * @throws Exception - * the server cannot be started, testing is not possible. - */ - public void setUp() throws Exception { - RecordingLogger.clear(); - log.clear(); - server.start(); - config.setSecurePort(getSecurePort()); - if (secureConfig != null) { - secureConfig.setSecurePort(getSecurePort()); - } - } - - /** - * Shutdown the server. - * - * @throws Exception - * the server refuses to halt, or wasn't running. - */ - public void tearDown() throws Exception { - RecordingLogger.clear(); - log.clear(); - server.stop(); - for (File f : filesToDelete) { - f.delete(); - } - filesToDelete.clear(); - } - - /** - * Get the URI to reference this server. - *

- * The returned URI includes the proper host name and port number, but does - * not contain a path. - * - * @return URI to reference this server's root context. - */ - public URI getURI() { - assertAlreadySetUp(); - String host = connector.getHost(); - if (host.contains(":") && !host.startsWith("[")) - host = "[" + host + "]"; - final String uri = "http://" + host + ":" + getPort(); - try { - return new URI(uri); - } catch (URISyntaxException e) { - throw new RuntimeException("Unexpected URI error on " + uri, e); - } - } - - /** - * Get port. - * - * @return the local port number the server is listening on. - */ - public int getPort() { - assertAlreadySetUp(); - return connector.getLocalPort(); - } - - /** - * Get secure port. - * - * @return the HTTPS port or -1 if not configured. - */ - public int getSecurePort() { - assertAlreadySetUp(); - return secureConnector != null ? secureConnector.getLocalPort() : -1; - } - - /** - * Get requests. - * - * @return all requests since the server was started. - */ - public List getRequests() { - return new ArrayList<>(log.getEvents()); - } - - /** - * Get requests. - * - * @param base - * base URI used to access the server. - * @param path - * the path to locate requests for, relative to {@code base}. - * @return all requests which match the given path. - */ - public List getRequests(URIish base, String path) { - return getRequests(HttpTestCase.join(base, path)); - } - - /** - * Get requests. - * - * @param path - * the path to locate requests for. - * @return all requests which match the given path. - */ - public List getRequests(String path) { - ArrayList r = new ArrayList<>(); - for (AccessEvent event : log.getEvents()) { - if (event.getPath().equals(path)) { - r.add(event); - } - } - return r; - } - - private void assertNotYetSetUp() { - assertFalse("server is not running", server.isRunning()); - } - - private void assertAlreadySetUp() { - assertTrue("server is running", server.isRunning()); - } } diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServerBase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServerBase.java new file mode 100644 index 00000000000..6a71f884ebb --- /dev/null +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServerBase.java @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2010, 2017 Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.junit.http; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.security.AbstractLoginService; +import org.eclipse.jetty.security.RolePrincipal; +import org.eclipse.jetty.security.UserPrincipal; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jgit.transport.URIish; + +/** + * Tiny web application server for unit testing. + *

+ * Tests should start the server in their {@code setUp()} method and stop the + * server in their {@code tearDown()} method. Only while started the server's + * URL and/or port number can be obtained. + *

+ * The Jetty security API for declaring authentication constraints differs + * between EE generations. That part is therefore isolated in the abstract + * {@link #configureAuthentication(ServletContextHandler, String[])} seam, which + * the concrete {@code AppServer} provides for its servlet generation. + */ +public abstract class AppServerBase { + /** Realm name for the secure access areas. */ + public static final String realm = "Secure Area"; + + /** Username for secured access areas. */ + public static final String username = "agitter"; + + /** Password for {@link #username} in secured access areas. */ + public static final String password = "letmein"; + + /** SSL keystore password; must have at least 6 characters. */ + private static final String keyPassword = "mykeys"; + + /** Role for authentication. */ + protected static final String authRole = "can-access"; + + static { + // Install a logger that throws warning messages. + // + final String prop = "org.eclipse.jetty.util.log.class"; + System.setProperty(prop, RecordingLogger.class.getName()); + } + + private final Server server; + + private final HttpConfiguration config; + + private final ServerConnector connector; + + private final HttpConfiguration secureConfig; + + private final ServerConnector secureConnector; + + /** Collection the servlet contexts are registered in. */ + protected final ContextHandlerCollection contexts; + + private final TestRequestLog log; + + private List filesToDelete = new ArrayList<>(); + + /** + * Constructor for AppServer. + */ + protected AppServerBase() { + this(0, -1); + } + + /** + * Constructor for AppServer. + * + * @param port + * the http port number; may be zero to allocate a port + * dynamically + */ + protected AppServerBase(int port) { + this(port, -1); + } + + /** + * Constructor for AppServer. + * + * @param port + * for http, may be zero to allocate a port dynamically + * @param sslPort + * for https,may be zero to allocate a port dynamically. If + * negative, the server will be set up without https support. + */ + protected AppServerBase(int port, int sslPort) { + server = new Server(); + + config = new HttpConfiguration(); + config.setSecureScheme("https"); + config.setSecurePort(0); + config.setOutputBufferSize(32768); + + connector = new ServerConnector(server, + new HttpConnectionFactory(config)); + connector.setPort(port); + String ip; + String hostName; + try { + final InetAddress me = InetAddress.getByName("localhost"); + ip = me.getHostAddress(); + connector.setHost(ip); + hostName = InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException e) { + throw new RuntimeException("Cannot find localhost", e); + } + + if (sslPort >= 0) { + SslContextFactory.Server sslContextFactory = createTestSslContextFactory( + hostName, ip); + secureConfig = new HttpConfiguration(config); + secureConfig.addCustomizer(new SecureRequestCustomizer()); + HttpConnectionFactory http11 = new HttpConnectionFactory( + secureConfig); + SslConnectionFactory tls = new SslConnectionFactory( + sslContextFactory, http11.getProtocol()); + secureConnector = new ServerConnector(server, tls, http11); + secureConnector.setPort(sslPort); + secureConnector.setHost(ip); + } else { + secureConfig = null; + secureConnector = null; + } + + contexts = new ContextHandlerCollection(); + + log = new TestRequestLog(); + log.setHandler(contexts); + + if (secureConnector == null) { + server.setConnectors(new Connector[] { connector }); + } else { + server.setConnectors( + new Connector[] { connector, secureConnector }); + } + server.setHandler(log); + } + + private SslContextFactory.Server createTestSslContextFactory( + String hostName, String ip) { + SslContextFactory.Server factory = new SslContextFactory.Server(); + + String dName = "CN=localhost,OU=JGit,O=Eclipse,ST=Ontario,L=Toronto,C=CA"; + + try { + File tmpDir = Files.createTempDirectory("jks").toFile(); + tmpDir.deleteOnExit(); + makePrivate(tmpDir); + File keyStore = new File(tmpDir, "keystore.jks"); + File keytool = new File( + new File(new File(System.getProperty("java.home")), "bin"), + "keytool"); + Runtime.getRuntime().exec( + new String[] { + keytool.getAbsolutePath(), // + "-keystore", keyStore.getAbsolutePath(), // + "-storepass", keyPassword, + "-alias", hostName, // + "-ext", "bc=ca:true", // + "-ext", + String.format( + "san=ip:%s,ip:127.0.0.1,ip:[::1],DNS:%s", + ip, hostName), // + "-genkeypair", // + "-keyalg", "RSA", // + "-keypass", keyPassword, // + "-dname", dName, // + "-validity", "2" // + }).waitFor(); + keyStore.deleteOnExit(); + makePrivate(keyStore); + filesToDelete.add(keyStore); + filesToDelete.add(tmpDir); + factory.setKeyStorePath(keyStore.getAbsolutePath()); + factory.setKeyStorePassword(keyPassword); + factory.setKeyManagerPassword(keyPassword); + factory.setTrustStorePath(keyStore.getAbsolutePath()); + factory.setTrustStorePassword(keyPassword); + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Cannot create ssl key/certificate", e); + } + return factory; + } + + private void makePrivate(File file) { + file.setReadable(false); + file.setWritable(false); + file.setExecutable(false); + file.setReadable(true, true); + file.setWritable(true, true); + if (file.isDirectory()) { + file.setExecutable(true, true); + } + } + + /** + * Create a new servlet context within the server. + *

+ * This method should be invoked before the server is started, once for each + * context the caller wants to register. + * + * @param path + * path of the context; use "/" for the root context if binding + * to the root is desired. + * @return the context to add servlets into. + * @since 7.8 + */ + public ServletContextHandler addContext(String path) { + assertNotYetSetUp(); + if ("".equals(path)) + path = "/"; + + ServletContextHandler ctx = new ServletContextHandler(); + ctx.setContextPath(path); + contexts.addHandler(ctx); + + return ctx; + } + + /** + * Configure basic authentication. + * + * @param ctx + * servlet context handler + * @param methods + * the methods + * @return servlet context handler + * @since 7.8 + */ + public ServletContextHandler authBasic(ServletContextHandler ctx, + String... methods) { + assertNotYetSetUp(); + configureAuthentication(ctx, methods); + return ctx; + } + + /** + * Install basic-authentication constraints on the given context. + *

+ * The Jetty security API used to build the constraints and attach the + * security handler differs between servlet generations, so each concrete + * {@code AppServer} implements this seam for its Jetty flavor. + * + * @param ctx + * servlet context handler to secure + * @param methods + * HTTP methods to constrain; empty constrains all methods + */ + protected abstract void configureAuthentication(ServletContextHandler ctx, + String[] methods); + + /** Login service mapping the single test user and role. */ + protected static class TestMappedLoginService extends AbstractLoginService { + private RolePrincipal role; + + protected final Map users = new ConcurrentHashMap<>(); + + TestMappedLoginService(String role) { + this.role = new RolePrincipal(role); + } + + @Override + protected void doStart() throws Exception { + UserPrincipal p = new UserPrincipal(username, + new Password(password)); + users.put(username, p); + super.doStart(); + } + + @Override + protected UserPrincipal loadUserInfo(String user) { + return users.get(user); + } + + @Override + protected List loadRoleInfo(UserPrincipal user) { + if (users.get(user.getName()) == null) { + return null; + } + return Collections.singletonList(role); + } + } + + /** + * Start the server on a random local port. + * + * @throws Exception + * the server cannot be started, testing is not possible. + */ + public void setUp() throws Exception { + RecordingLogger.clear(); + log.clear(); + server.start(); + config.setSecurePort(getSecurePort()); + if (secureConfig != null) { + secureConfig.setSecurePort(getSecurePort()); + } + } + + /** + * Shutdown the server. + * + * @throws Exception + * the server refuses to halt, or wasn't running. + */ + public void tearDown() throws Exception { + RecordingLogger.clear(); + log.clear(); + server.stop(); + for (File f : filesToDelete) { + f.delete(); + } + filesToDelete.clear(); + } + + /** + * Get the URI to reference this server. + *

+ * The returned URI includes the proper host name and port number, but does + * not contain a path. + * + * @return URI to reference this server's root context. + */ + public URI getURI() { + assertAlreadySetUp(); + String host = connector.getHost(); + if (host.contains(":") && !host.startsWith("[")) + host = "[" + host + "]"; + final String uri = "http://" + host + ":" + getPort(); + try { + return new URI(uri); + } catch (URISyntaxException e) { + throw new RuntimeException("Unexpected URI error on " + uri, e); + } + } + + /** + * Get port. + * + * @return the local port number the server is listening on. + */ + public int getPort() { + assertAlreadySetUp(); + return connector.getLocalPort(); + } + + /** + * Get secure port. + * + * @return the HTTPS port or -1 if not configured. + */ + public int getSecurePort() { + assertAlreadySetUp(); + return secureConnector != null ? secureConnector.getLocalPort() : -1; + } + + /** + * Get requests. + * + * @return all requests since the server was started. + */ + public List getRequests() { + return new ArrayList<>(log.getEvents()); + } + + /** + * Get requests. + * + * @param base + * base URI used to access the server. + * @param path + * the path to locate requests for, relative to {@code base}. + * @return all requests which match the given path. + */ + public List getRequests(URIish base, String path) { + return getRequests(HttpTestCase.join(base, path)); + } + + /** + * Get requests. + * + * @param path + * the path to locate requests for. + * @return all requests which match the given path. + */ + public List getRequests(String path) { + ArrayList r = new ArrayList<>(); + for (AccessEvent event : log.getEvents()) { + if (event.getPath().equals(path)) { + r.add(event); + } + } + return r; + } + + private void assertNotYetSetUp() { + assertFalse("server is not running", server.isRunning()); + } + + private void assertAlreadySetUp() { + assertTrue("server is running", server.isRunning()); + } +} diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java index f399471b398..ef56b6cfd61 100644 --- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.Set; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; @@ -109,7 +109,7 @@ protected URIish toURIish(String path) throws URISyntaxException { * @return the warnings (if any) from the last execution * @throws URISyntaxException * if URI is invalid - * @since 7.0 + * @since 7.8 */ protected URIish toURIish(ServletContextHandler app, String name) throws URISyntaxException { diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java index bce41383d17..63f7ddf39c0 100644 --- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/SimpleHttpServer.java @@ -15,8 +15,8 @@ import jakarta.servlet.http.HttpServletRequest; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.lib.Repository; diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF index 012f00bf72f..77e5c1d924b 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF @@ -3,47 +3,47 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: org.apache.sshd.common;version="[2.17.1,2.18.0)", - org.apache.sshd.common.config.keys;version="[2.17.1,2.18.0)", - org.apache.sshd.common.file.virtualfs;version="[2.17.1,2.18.0)", - org.apache.sshd.common.helpers;version="[2.17.1,2.18.0)", - org.apache.sshd.common.io;version="[2.17.1,2.18.0)", - org.apache.sshd.common.kex;version="[2.17.1,2.18.0)", - org.apache.sshd.common.keyprovider;version="[2.17.1,2.18.0)", - org.apache.sshd.common.session;version="[2.17.1,2.18.0)", - org.apache.sshd.common.signature;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.buffer;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.logging;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.security;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.threads;version="[2.17.1,2.18.0)", - org.apache.sshd.core;version="[2.17.1,2.18.0)", - org.apache.sshd.server;version="[2.17.1,2.18.0)", - org.apache.sshd.server.auth;version="[2.17.1,2.18.0)", - org.apache.sshd.server.auth.gss;version="[2.17.1,2.18.0)", - org.apache.sshd.server.auth.keyboard;version="[2.17.1,2.18.0)", - org.apache.sshd.server.auth.password;version="[2.17.1,2.18.0)", - org.apache.sshd.server.command;version="[2.17.1,2.18.0)", - org.apache.sshd.server.session;version="[2.17.1,2.18.0)", - org.apache.sshd.server.shell;version="[2.17.1,2.18.0)", - org.apache.sshd.server.subsystem;version="[2.17.1,2.18.0)", - org.apache.sshd.sftp;version="[2.17.1,2.18.0)", - org.apache.sshd.sftp.server;version="[2.17.1,2.18.0)", - org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", +Import-Package: org.apache.sshd.common;version="[2.19.0,2.20.0)", + org.apache.sshd.common.config.keys;version="[2.19.0,2.20.0)", + org.apache.sshd.common.file.virtualfs;version="[2.19.0,2.20.0)", + org.apache.sshd.common.helpers;version="[2.19.0,2.20.0)", + org.apache.sshd.common.io;version="[2.19.0,2.20.0)", + org.apache.sshd.common.kex;version="[2.19.0,2.20.0)", + org.apache.sshd.common.keyprovider;version="[2.19.0,2.20.0)", + org.apache.sshd.common.session;version="[2.19.0,2.20.0)", + org.apache.sshd.common.signature;version="[2.19.0,2.20.0)", + org.apache.sshd.common.util.buffer;version="[2.19.0,2.20.0)", + org.apache.sshd.common.util.logging;version="[2.19.0,2.20.0)", + org.apache.sshd.common.util.security;version="[2.19.0,2.20.0)", + org.apache.sshd.common.util.threads;version="[2.19.0,2.20.0)", + org.apache.sshd.core;version="[2.19.0,2.20.0)", + org.apache.sshd.server;version="[2.19.0,2.20.0)", + org.apache.sshd.server.auth;version="[2.19.0,2.20.0)", + org.apache.sshd.server.auth.gss;version="[2.19.0,2.20.0)", + org.apache.sshd.server.auth.keyboard;version="[2.19.0,2.20.0)", + org.apache.sshd.server.auth.password;version="[2.19.0,2.20.0)", + org.apache.sshd.server.command;version="[2.19.0,2.20.0)", + org.apache.sshd.server.session;version="[2.19.0,2.20.0)", + org.apache.sshd.server.shell;version="[2.19.0,2.20.0)", + org.apache.sshd.server.subsystem;version="[2.19.0,2.20.0)", + org.apache.sshd.sftp;version="[2.19.0,2.20.0)", + org.apache.sshd.sftp.server;version="[2.19.0,2.20.0)", + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.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.6.0" +Export-Package: org.eclipse.jgit.junit.ssh;version="7.8.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 9c1adcb4a2d..d52282f694c 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml index 8d6d068adcb..5ac4ae7db0d 100644 --- a/org.eclipse.jgit.junit.ssh/pom.xml +++ b/org.eclipse.jgit.junit.ssh/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.junit.ssh diff --git a/org.eclipse.jgit.junit/BUILD b/org.eclipse.jgit.junit/BUILD index f4a7165dbbb..8879cd98b69 100644 --- a/org.eclipse.jgit.junit/BUILD +++ b/org.eclipse.jgit.junit/BUILD @@ -7,7 +7,10 @@ java_library( testonly = 1, srcs = glob(["src/**/*.java"]), resource_strip_prefix = "org.eclipse.jgit.junit/resources", - resources = glob(["resources/**"], allow_empty=True), + 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 bf528656d9e..6d7b85e20cd 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF @@ -3,38 +3,38 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.dircache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.merge;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="7.6.0", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.io;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.time;version="[7.6.0,7.7.0)", +Import-Package: org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.dircache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.merge;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="7.8.0", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.io;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.time;version="[7.8.0,7.9.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.6.0"; +Export-Package: org.eclipse.jgit.junit;version="7.8.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -47,4 +47,4 @@ Export-Package: org.eclipse.jgit.junit;version="7.6.0"; org.junit.runners.model, org.junit.runner, org.eclipse.jgit.util.time", - org.eclipse.jgit.junit.time;version="7.6.0";uses:="org.eclipse.jgit.util.time" + org.eclipse.jgit.junit.time;version="7.8.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 cb07dc904c1..4ccd459f50a 100644 --- a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.junit;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.junit;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index fa798c8ae80..ac83f533922 100644 --- a/org.eclipse.jgit.junit/pom.xml +++ b/org.eclipse.jgit.junit/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.junit diff --git a/org.eclipse.jgit.lfs.server.ee8/BUILD b/org.eclipse.jgit.lfs.server.ee8/BUILD new file mode 100644 index 00000000000..b07dae2cde3 --- /dev/null +++ b/org.eclipse.jgit.lfs.server.ee8/BUILD @@ -0,0 +1,32 @@ +load("@rules_java//java:defs.bzl", "java_library") +load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar") + +package(default_visibility = ["//visibility:public"]) + +transform_srcjar( + name = "jgit-lfs-server-ee8-srcs", + direction = "to_javax", + sources = ["//org.eclipse.jgit.lfs.server:srcs"], + src_prefix = "org.eclipse.jgit.lfs.server/src/", +) + +filegroup( + name = "jgit-lfs-server-ee8-srcjar", + srcs = [":jgit-lfs-server-ee8-srcs"], +) + +java_library( + name = "jgit-lfs-server-ee8", + srcs = [":jgit-lfs-server-ee8-srcs"], + resource_strip_prefix = "org.eclipse.jgit.lfs.server/resources", + resources = ["//org.eclipse.jgit.lfs.server:jgit-lfs-server-resources"], + deps = [ + "//lib:gson", + "//lib:httpcore", + "//lib:javax-servlet-api", + "//lib:slf4j-api", + "//org.eclipse.jgit.http.apache:http-apache", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.lfs:jgit-lfs", + ], +) diff --git a/org.eclipse.jgit.lfs.server.test.ee8/BUILD b/org.eclipse.jgit.lfs.server.test.ee8/BUILD new file mode 100644 index 00000000000..bb93b79374b --- /dev/null +++ b/org.eclipse.jgit.lfs.server.test.ee8/BUILD @@ -0,0 +1,65 @@ +load("@rules_java//java:defs.bzl", "java_library") +load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests") +load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar") + +transform_srcjar( + name = "test-srcs", + testonly = 1, + direction = "to_javax", + sources = ["//org.eclipse.jgit.lfs.server.test:test-srcs"], + src_prefix = "org.eclipse.jgit.lfs.server.test/tst/", + visibility = ["//tools/jgit-ee8:__pkg__"], +) + +transform_srcjar( + name = "base-test-srcs", + testonly = 1, + direction = "to_javax", + sources = ["//org.eclipse.jgit.lfs.server.test:base-test-srcs"], + src_prefix = "org.eclipse.jgit.lfs.server.test/tst/", +) + +# Keep the helper/base class separate: the canonical LfsServerTest is compiled +# into the helper jar, while the remaining tests are executed from the EE8 +# suite target. +DEPS = [ + "//org.eclipse.jgit.lfs.test:helpers", + "//org.eclipse.jgit:jgit", + "//org.eclipse.jgit.junit:junit", + "//org.eclipse.jgit.junit.http.ee8:junit-http-ee8", + "//org.eclipse.jgit.lfs:jgit-lfs", + "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8", + "//lib:commons-logging", + "//lib:httpcore", + "//lib:httpclient", + "//lib:junit", + "//lib:jetty-http", + "//lib:jetty-io", + "//lib:jetty-server", + "//lib:jetty-servlet-ee8", + "//lib:jetty-security", + "//lib:jetty-security-ee8", + "//lib:jetty-util", + "//lib:javax-servlet-api", +] + +junit_tests( + name = "lfs_server", + jvm_flags = [ + "-Xmx512m", + "-Dfile.encoding=UTF-8", + ], + suite_srcs = ["//org.eclipse.jgit.lfs.server.test:nonbase-test-srcs"], + tags = ["lfs-server"], + srcs = [":test-srcs"], + deps = DEPS + [ + ":helpers", + ], +) + +java_library( + name = "helpers", + testonly = 1, + srcs = [":base-test-srcs"], + deps = DEPS, +) diff --git a/org.eclipse.jgit.lfs.server.test/BUILD b/org.eclipse.jgit.lfs.server.test/BUILD index 76a0870a881..4b698048694 100644 --- a/org.eclipse.jgit.lfs.server.test/BUILD +++ b/org.eclipse.jgit.lfs.server.test/BUILD @@ -6,6 +6,35 @@ load("@rules_java//java:defs.bzl", "java_library") TEST_BASE = ["tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java"] +TEST_SRCS = glob(["tst/**/*.java"]) + +filegroup( + name = "test-srcs", + testonly = 1, + srcs = TEST_SRCS, + visibility = [ + "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) + +filegroup( + name = "base-test-srcs", + testonly = 1, + srcs = TEST_BASE, + visibility = ["//org.eclipse.jgit.lfs.server.test.ee8:__pkg__"], +) + +filegroup( + name = "nonbase-test-srcs", + testonly = 1, + srcs = glob( + ["tst/**/*.java"], + exclude = TEST_BASE, + ), + visibility = ["//org.eclipse.jgit.lfs.server.test.ee8:__pkg__"], +) + DEPS = [ "//org.eclipse.jgit.lfs.test:helpers", "//org.eclipse.jgit:jgit", @@ -23,7 +52,7 @@ DEPS = [ "//lib:jetty-servlet", "//lib:jetty-security", "//lib:jetty-util", - "//lib:servlet-api", + "//lib:jakarta-servlet-api", ] junit_tests( 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 9b0f742fee6..5a923f51f77 100644 --- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF @@ -3,19 +3,19 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", - jakarta.servlet.http;version="[6.0.0,7.0.0)", +Import-Package: jakarta.servlet;version="[6.1.0,7.0.0)", + jakarta.servlet.http;version="[6.1.0,7.0.0)", org.apache.http;version="[4.4.0,5.0.0)", org.apache.http.client;version="[4.4.0,5.0.0)", org.apache.http.client.methods;version="[4.4.0,5.0.0)", org.apache.http.entity;version="[4.4.0,5.0.0)", org.apache.http.impl.client;version="[4.4.0,5.0.0)", - org.eclipse.jetty.ee10.servlet;version="[12.0.0,13.0.0)", + org.eclipse.jetty.ee11.servlet;version="[12.0.0,13.0.0)", org.eclipse.jetty.http;version="[12.0.0,13.0.0)", org.eclipse.jetty.io;version="[12.0.0,13.0.0)", org.eclipse.jetty.security;version="[12.0.0,13.0.0)", @@ -27,24 +27,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.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.server;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.server.fs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.test;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.server;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.server.fs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.test;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.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 3cdda74bfd7..3620dd75266 100644 --- a/org.eclipse.jgit.lfs.server.test/pom.xml +++ b/org.eclipse.jgit.lfs.server.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.lfs.server.test @@ -74,8 +74,8 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet + org.eclipse.jetty.ee11 + jetty-ee11-servlet test diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java index 9a49023fcba..f1b070c7586 100644 --- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java +++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java @@ -39,8 +39,8 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.junit.http.AppServer; import org.eclipse.jgit.lfs.errors.LfsException; diff --git a/org.eclipse.jgit.lfs.server/BUILD b/org.eclipse.jgit.lfs.server/BUILD index cd1831b8320..d6b08a6ee94 100644 --- a/org.eclipse.jgit.lfs.server/BUILD +++ b/org.eclipse.jgit.lfs.server/BUILD @@ -2,15 +2,29 @@ load("@rules_java//java:defs.bzl", "java_library") package(default_visibility = ["//visibility:public"]) +filegroup( + name = "srcs", + srcs = glob(["src/**/*.java"]), + visibility = [ + "//org.eclipse.jgit.lfs.server.ee8:__pkg__", + "//tools/jgit-ee8:__pkg__", + ], +) + +filegroup( + name = "jgit-lfs-server-resources", + srcs = glob(["resources/**"]), +) + java_library( name = "jgit-lfs-server", - srcs = glob(["src/**/*.java"]), + srcs = [":srcs"], resource_strip_prefix = "org.eclipse.jgit.lfs.server/resources", - resources = glob(["resources/**"]), + resources = [":jgit-lfs-server-resources"], deps = [ "//lib:gson", "//lib:httpcore", - "//lib:servlet-api", + "//lib:jakarta-servlet-api", "//lib:slf4j-api", "//org.eclipse.jgit.http.apache:http-apache", "//org.eclipse.jgit:jgit", diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF index b0ee6b4beb0..68d7877451a 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF @@ -3,37 +3,37 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Export-Package: org.eclipse.jgit.lfs.server;version="7.6.0"; +Export-Package: org.eclipse.jgit.lfs.server;version="7.8.0"; uses:="jakarta.servlet.http, org.eclipse.jgit.lfs.lib", - org.eclipse.jgit.lfs.server.fs;version="7.6.0"; + org.eclipse.jgit.lfs.server.fs;version="7.8.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.6.0";x-internal:=true, - org.eclipse.jgit.lfs.server.s3;version="7.6.0"; + org.eclipse.jgit.lfs.server.internal;version="7.8.0";x-internal:=true, + org.eclipse.jgit.lfs.server.s3;version="7.8.0"; uses:="org.eclipse.jgit.lfs.server, org.eclipse.jgit.lfs.lib" Import-Package: com.google.gson;version="[2.8.0,3.0.0)", - jakarta.servlet;version="[6.0.0,7.0.0)", - jakarta.servlet.annotation;version="[6.0.0,7.0.0)", - jakarta.servlet.http;version="[6.0.0,7.0.0)", + jakarta.servlet;version="[6.1.0,7.0.0)", + jakarta.servlet.annotation;version="[6.1.0,7.0.0)", + jakarta.servlet.http;version="[6.1.0,7.0.0)", org.apache.http;version="[4.3.0,5.0.0)", - org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http.apache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http.apache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.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 c2a8147e8ee..5e4c9cf7bb6 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml index 1b4a73b4de0..67b1bf22e6a 100644 --- a/org.eclipse.jgit.lfs.server/pom.xml +++ b/org.eclipse.jgit.lfs.server/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.lfs.server diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF index d79ae9a34fc..82b1403fc3c 100644 --- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF @@ -3,29 +3,29 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: org.eclipse.jgit.api;version="[7.6.0,7.7.0)", - org.eclipse.jgit.attributes;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.dfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", +Import-Package: org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.attributes;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.dfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.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.6.0";x-friends:="org.eclipse.jgit.lfs.server.test" +Export-Package: org.eclipse.jgit.lfs.test;version="7.8.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 4f9de97f59b..2380339358c 100644 --- a/org.eclipse.jgit.lfs.test/pom.xml +++ b/org.eclipse.jgit.lfs.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.lfs.test diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF index 44d84770ecd..4a1012758f5 100644 --- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF @@ -3,33 +3,33 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs Bundle-SymbolicName: org.eclipse.jgit.lfs -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Export-Package: org.eclipse.jgit.lfs;version="7.6.0", - org.eclipse.jgit.lfs.errors;version="7.6.0", - org.eclipse.jgit.lfs.internal;version="7.6.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.6.0" +Export-Package: org.eclipse.jgit.lfs;version="7.8.0", + org.eclipse.jgit.lfs.errors;version="7.8.0", + org.eclipse.jgit.lfs.internal;version="7.8.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.8.0" 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.6.0,7.7.0)";resolution:=optional, - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.attributes;version="[7.6.0,7.7.0)", - org.eclipse.jgit.diff;version="[7.6.0,7.7.0)", - org.eclipse.jgit.dircache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.hooks;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.io;version="[7.6.0,7.7.0)" + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)";resolution:=optional, + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.attributes;version="[7.8.0,7.9.0)", + org.eclipse.jgit.diff;version="[7.8.0,7.9.0)", + org.eclipse.jgit.dircache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.hooks;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.io;version="[7.8.0,7.9.0)" diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF index cdc7cf9b7bf..b468bc3b2b2 100644 --- a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml index 803606acf18..78d3b3990e0 100644 --- a/org.eclipse.jgit.lfs/pom.xml +++ b/org.eclipse.jgit.lfs/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.lfs 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 c5521eea303..1c04cc8f141 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 @@ 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 95ec4e95b99..62ebf8218d2 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 @@ org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 1518beb7854..17a3e8f06a9 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 @@ @@ -23,7 +23,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 b9815d6a251..81e9291d983 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 @@ @@ -23,7 +23,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 efbf3c03d15..4bdf2678fb3 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 @@ @@ -24,7 +24,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 fef54ecbba2..811948aa1fd 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 @@ @@ -23,7 +23,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 868aa02c2db..feb04004e08 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 @@ @@ -35,9 +35,9 @@ version="0.0.0"/> - - - + + + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 08294c7184b..e6a9c638415 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml @@ -105,10 +105,10 @@ - + - + @@ -147,7 +147,7 @@ - + @@ -216,6 +216,12 @@ + + + + + + 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 5c71af5fc99..4b597ea6f45 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 @@ org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.repository 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 bfb53604c02..59085683575 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 @@ @@ -23,7 +23,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature @@ -30,7 +30,7 @@ org.eclipse.jgit.feature org.eclipse.jgit - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT 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 cc7a9d67614..2cd6ac85f6e 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 @@ @@ -23,7 +23,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 ab0775e3421..c14e4a31fd4 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 @@ @@ -23,7 +23,7 @@ - + org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.feature 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 2f519a09985..a73d53ecacf 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,7 +1,7 @@ - + @@ -39,7 +39,7 @@ org.tukaani xz - 1.11 + 1.12 jar @@ -49,13 +49,19 @@ org.slf4j slf4j-api - 2.0.17 + 2.0.18 jar org.slf4j slf4j-simple - 2.0.17 + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 jar @@ -65,13 +71,13 @@ org.apache.sshd sshd-osgi - 2.17.1 + 2.19.0 jar org.apache.sshd sshd-sftp - 2.17.1 + 2.19.0 jar @@ -81,7 +87,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 jar @@ -91,13 +97,13 @@ net.java.dev.jna jna - 5.18.1 + 5.19.1 jar net.java.dev.jna jna-platform - 5.18.1 + 5.19.1 jar @@ -105,51 +111,51 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet - 12.1.5 + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 jar org.eclipse.jetty jetty-http - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-io - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-security - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-server - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-session - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util-ajax - 12.1.5 + 12.1.11 jar @@ -185,7 +191,7 @@ com.google.code.gson gson - 2.13.2 + 2.14.0 jar @@ -195,13 +201,13 @@ net.bytebuddy byte-buddy - 1.18.4 + 1.18.11 jar net.bytebuddy byte-buddy-agent - 1.18.4 + 1.18.11 jar @@ -211,25 +217,25 @@ org.bouncycastle bcpg-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcprov-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcpkix-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcutil-jdk18on - 1.83 + 1.85 jar @@ -259,7 +265,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 jar @@ -277,13 +283,13 @@ commons-io commons-io - 2.21.0 + 2.22.0 jar commons-logging commons-logging - 1.3.5 + 1.4.0 jar 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 index abaa5a4c572..21e3598257a 100644 --- 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 @@ -1,7 +1,7 @@ - + @@ -39,7 +39,7 @@ org.tukaani xz - 1.11 + 1.12 jar @@ -49,13 +49,19 @@ org.slf4j slf4j-api - 2.0.17 + 2.0.18 jar org.slf4j slf4j-simple - 2.0.17 + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 jar @@ -65,13 +71,13 @@ org.apache.sshd sshd-osgi - 2.17.1 + 2.19.0 jar org.apache.sshd sshd-sftp - 2.17.1 + 2.19.0 jar @@ -81,7 +87,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 jar @@ -91,13 +97,13 @@ net.java.dev.jna jna - 5.18.1 + 5.19.1 jar net.java.dev.jna jna-platform - 5.18.1 + 5.19.1 jar @@ -105,51 +111,51 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet - 12.1.5 + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 jar org.eclipse.jetty jetty-http - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-io - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-security - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-server - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-session - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util-ajax - 12.1.5 + 12.1.11 jar @@ -185,7 +191,7 @@ com.google.code.gson gson - 2.13.2 + 2.14.0 jar @@ -195,13 +201,13 @@ net.bytebuddy byte-buddy - 1.18.4 + 1.18.11 jar net.bytebuddy byte-buddy-agent - 1.18.4 + 1.18.11 jar @@ -211,25 +217,25 @@ org.bouncycastle bcpg-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcprov-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcpkix-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcutil-jdk18on - 1.83 + 1.85 jar @@ -259,7 +265,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 jar @@ -277,13 +283,13 @@ commons-io commons-io - 2.21.0 + 2.22.0 jar commons-logging commons-logging - 1.3.5 + 1.4.0 jar 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 index c6a05ea4061..d9ec645d946 100644 --- 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 @@ -1,7 +1,7 @@ - + @@ -39,7 +39,7 @@ org.tukaani xz - 1.11 + 1.12 jar @@ -49,13 +49,19 @@ org.slf4j slf4j-api - 2.0.17 + 2.0.18 jar org.slf4j slf4j-simple - 2.0.17 + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 jar @@ -65,13 +71,13 @@ org.apache.sshd sshd-osgi - 2.17.1 + 2.19.0 jar org.apache.sshd sshd-sftp - 2.17.1 + 2.19.0 jar @@ -81,7 +87,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 jar @@ -91,13 +97,13 @@ net.java.dev.jna jna - 5.18.1 + 5.19.1 jar net.java.dev.jna jna-platform - 5.18.1 + 5.19.1 jar @@ -105,51 +111,51 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet - 12.1.5 + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 jar org.eclipse.jetty jetty-http - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-io - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-security - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-server - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-session - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util-ajax - 12.1.5 + 12.1.11 jar @@ -185,7 +191,7 @@ com.google.code.gson gson - 2.13.2 + 2.14.0 jar @@ -195,13 +201,13 @@ net.bytebuddy byte-buddy - 1.18.4 + 1.18.11 jar net.bytebuddy byte-buddy-agent - 1.18.4 + 1.18.11 jar @@ -211,25 +217,25 @@ org.bouncycastle bcpg-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcprov-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcpkix-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcutil-jdk18on - 1.83 + 1.85 jar @@ -259,7 +265,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 jar @@ -277,13 +283,13 @@ commons-io commons-io - 2.21.0 + 2.22.0 jar commons-logging commons-logging - 1.3.5 + 1.4.0 jar diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target index a4b0cac3128..890f285aeac 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target @@ -1,7 +1,7 @@ - + @@ -39,7 +39,7 @@ org.tukaani xz - 1.11 + 1.12 jar @@ -49,13 +49,19 @@ org.slf4j slf4j-api - 2.0.17 + 2.0.18 jar org.slf4j slf4j-simple - 2.0.17 + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 jar @@ -65,13 +71,13 @@ org.apache.sshd sshd-osgi - 2.17.1 + 2.19.0 jar org.apache.sshd sshd-sftp - 2.17.1 + 2.19.0 jar @@ -81,7 +87,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 jar @@ -91,13 +97,13 @@ net.java.dev.jna jna - 5.18.1 + 5.19.1 jar net.java.dev.jna jna-platform - 5.18.1 + 5.19.1 jar @@ -105,51 +111,51 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet - 12.1.5 + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 jar org.eclipse.jetty jetty-http - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-io - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-security - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-server - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-session - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util-ajax - 12.1.5 + 12.1.11 jar @@ -185,7 +191,7 @@ com.google.code.gson gson - 2.13.2 + 2.14.0 jar @@ -195,13 +201,13 @@ net.bytebuddy byte-buddy - 1.18.4 + 1.18.11 jar net.bytebuddy byte-buddy-agent - 1.18.4 + 1.18.11 jar @@ -211,25 +217,25 @@ org.bouncycastle bcpg-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcprov-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcpkix-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcutil-jdk18on - 1.83 + 1.85 jar @@ -259,7 +265,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 jar @@ -277,13 +283,13 @@ commons-io commons-io - 2.21.0 + 2.22.0 jar commons-logging commons-logging - 1.3.5 + 1.4.0 jar diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target index e75ee6d2b23..644e0930453 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target @@ -1,7 +1,7 @@ - + @@ -39,7 +39,7 @@ org.tukaani xz - 1.11 + 1.12 jar @@ -49,13 +49,19 @@ org.slf4j slf4j-api - 2.0.17 + 2.0.18 jar org.slf4j slf4j-simple - 2.0.17 + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 jar @@ -65,13 +71,13 @@ org.apache.sshd sshd-osgi - 2.17.1 + 2.19.0 jar org.apache.sshd sshd-sftp - 2.17.1 + 2.19.0 jar @@ -81,7 +87,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 jar @@ -91,13 +97,13 @@ net.java.dev.jna jna - 5.18.1 + 5.19.1 jar net.java.dev.jna jna-platform - 5.18.1 + 5.19.1 jar @@ -105,51 +111,51 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet - 12.1.5 + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 jar org.eclipse.jetty jetty-http - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-io - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-security - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-server - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-session - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util-ajax - 12.1.5 + 12.1.11 jar @@ -185,7 +191,7 @@ com.google.code.gson gson - 2.13.2 + 2.14.0 jar @@ -195,13 +201,13 @@ net.bytebuddy byte-buddy - 1.18.4 + 1.18.11 jar net.bytebuddy byte-buddy-agent - 1.18.4 + 1.18.11 jar @@ -211,25 +217,25 @@ org.bouncycastle bcpg-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcprov-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcpkix-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcutil-jdk18on - 1.83 + 1.85 jar @@ -259,7 +265,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 jar @@ -277,13 +283,13 @@ commons-io commons-io - 2.21.0 + 2.22.0 jar commons-logging commons-logging - 1.3.5 + 1.4.0 jar diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target index 5836dd394a4..13eb7a30b75 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target @@ -1,7 +1,7 @@ - + @@ -24,22 +24,22 @@ - - + + - + org.tukaani xz - 1.11 + 1.12 jar @@ -49,13 +49,19 @@ org.slf4j slf4j-api - 2.0.17 + 2.0.18 jar org.slf4j slf4j-simple - 2.0.17 + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 jar @@ -65,13 +71,13 @@ org.apache.sshd sshd-osgi - 2.17.1 + 2.19.0 jar org.apache.sshd sshd-sftp - 2.17.1 + 2.19.0 jar @@ -81,7 +87,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 jar @@ -91,13 +97,13 @@ net.java.dev.jna jna - 5.18.1 + 5.19.1 jar net.java.dev.jna jna-platform - 5.18.1 + 5.19.1 jar @@ -105,51 +111,51 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet - 12.1.5 + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 jar org.eclipse.jetty jetty-http - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-io - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-security - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-server - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-session - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util - 12.1.5 + 12.1.11 jar org.eclipse.jetty jetty-util-ajax - 12.1.5 + 12.1.11 jar @@ -185,7 +191,7 @@ com.google.code.gson gson - 2.13.2 + 2.14.0 jar @@ -195,13 +201,13 @@ net.bytebuddy byte-buddy - 1.18.4 + 1.18.11 jar net.bytebuddy byte-buddy-agent - 1.18.4 + 1.18.11 jar @@ -211,25 +217,25 @@ org.bouncycastle bcpg-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcprov-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcpkix-jdk18on - 1.83 + 1.85 jar org.bouncycastle bcutil-jdk18on - 1.83 + 1.85 jar @@ -259,7 +265,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 jar @@ -277,13 +283,13 @@ commons-io commons-io - 2.21.0 + 2.22.0 jar commons-logging commons-logging - 1.3.5 + 1.4.0 jar diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd index 0b32b1b9cac..fb0fc7eac2a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd @@ -3,6 +3,6 @@ target "jgit-4.39" with source configurePhase include "orbit/orbit-4.39.tpd" include "maven/dependencies.tpd" -location "https://download.eclipse.org/staging/2026-03/" { +location "https://download.eclipse.org/releases/2026-03/" { org.eclipse.osgi lazy } diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.target new file mode 100644 index 00000000000..3669f822ff3 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.target @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.tukaani + xz + 1.12 + jar + + + + + + + org.slf4j + slf4j-api + 2.0.18 + jar + + + org.slf4j + slf4j-simple + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 + jar + + + + + + + org.apache.sshd + sshd-osgi + 2.19.0 + jar + + + org.apache.sshd + sshd-sftp + 2.19.0 + jar + + + + + + + org.mockito + mockito-core + 5.23.0 + jar + + + + + + + net.java.dev.jna + jna + 5.19.1 + jar + + + net.java.dev.jna + jna-platform + 5.19.1 + jar + + + + + + + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 + jar + + + org.eclipse.jetty + jetty-http + 12.1.11 + jar + + + org.eclipse.jetty + jetty-io + 12.1.11 + jar + + + org.eclipse.jetty + jetty-security + 12.1.11 + jar + + + org.eclipse.jetty + jetty-server + 12.1.11 + jar + + + org.eclipse.jetty + jetty-session + 12.1.11 + jar + + + org.eclipse.jetty + jetty-util + 12.1.11 + jar + + + org.eclipse.jetty + jetty-util-ajax + 12.1.11 + jar + + + jakarta.servlet + jakarta.servlet-api + 6.1.0 + jar + + + + + + + com.googlecode.javaewah + JavaEWAH + 1.2.3 + jar + + + + + + + org.hamcrest + hamcrest + 3.0 + jar + + + + + + + com.google.code.gson + gson + 2.14.0 + jar + + + + + + + net.bytebuddy + byte-buddy + 1.18.11 + jar + + + net.bytebuddy + byte-buddy-agent + 1.18.11 + jar + + + + + + + org.bouncycastle + bcpg-jdk18on + 1.85 + jar + + + org.bouncycastle + bcprov-jdk18on + 1.85 + jar + + + org.bouncycastle + bcpkix-jdk18on + 1.85 + jar + + + org.bouncycastle + bcutil-jdk18on + 1.85 + jar + + + + + + + org.assertj + assertj-core + 3.27.7 + jar + + + + + + + args4j + args4j + 2.37 + jar + + + + + + + commons-codec + commons-codec + 1.22.1 + jar + + + org.apache.commons + commons-compress + 1.28.0 + jar + + + org.apache.commons + commons-lang3 + 3.20.0 + jar + + + commons-io + commons-io + 2.22.0 + jar + + + commons-logging + commons-logging + 1.4.0 + jar + + + + + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.tpd new file mode 100644 index 00000000000..267a671766e --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.tpd @@ -0,0 +1,8 @@ +target "jgit-4.40" with source configurePhase + +include "orbit/orbit-4.40.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/releases/2026-06/" { + org.eclipse.osgi lazy +} diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.41.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.41.target new file mode 100644 index 00000000000..0fe9ebc4109 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.41.target @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.tukaani + xz + 1.12 + jar + + + + + + + org.slf4j + slf4j-api + 2.0.18 + jar + + + org.slf4j + slf4j-simple + 2.0.18 + jar + + + org.slf4j + jcl-over-slf4j + 2.0.18 + jar + + + + + + + org.apache.sshd + sshd-osgi + 2.19.0 + jar + + + org.apache.sshd + sshd-sftp + 2.19.0 + jar + + + + + + + org.mockito + mockito-core + 5.23.0 + jar + + + + + + + net.java.dev.jna + jna + 5.19.1 + jar + + + net.java.dev.jna + jna-platform + 5.19.1 + jar + + + + + + + org.eclipse.jetty.ee11 + jetty-ee11-servlet + 12.1.11 + jar + + + org.eclipse.jetty + jetty-http + 12.1.11 + jar + + + org.eclipse.jetty + jetty-io + 12.1.11 + jar + + + org.eclipse.jetty + jetty-security + 12.1.11 + jar + + + org.eclipse.jetty + jetty-server + 12.1.11 + jar + + + org.eclipse.jetty + jetty-session + 12.1.11 + jar + + + org.eclipse.jetty + jetty-util + 12.1.11 + jar + + + org.eclipse.jetty + jetty-util-ajax + 12.1.11 + jar + + + jakarta.servlet + jakarta.servlet-api + 6.1.0 + jar + + + + + + + com.googlecode.javaewah + JavaEWAH + 1.2.3 + jar + + + + + + + org.hamcrest + hamcrest + 3.0 + jar + + + + + + + com.google.code.gson + gson + 2.14.0 + jar + + + + + + + net.bytebuddy + byte-buddy + 1.18.11 + jar + + + net.bytebuddy + byte-buddy-agent + 1.18.11 + jar + + + + + + + org.bouncycastle + bcpg-jdk18on + 1.85 + jar + + + org.bouncycastle + bcprov-jdk18on + 1.85 + jar + + + org.bouncycastle + bcpkix-jdk18on + 1.85 + jar + + + org.bouncycastle + bcutil-jdk18on + 1.85 + jar + + + + + + + org.assertj + assertj-core + 3.27.7 + jar + + + + + + + args4j + args4j + 2.37 + jar + + + + + + + commons-codec + commons-codec + 1.22.1 + jar + + + org.apache.commons + commons-compress + 1.28.0 + jar + + + org.apache.commons + commons-lang3 + 3.20.0 + jar + + + commons-io + commons-io + 2.22.0 + jar + + + commons-logging + commons-logging + 1.4.0 + jar + + + + + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.41.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.41.tpd new file mode 100644 index 00000000000..1670b1bc762 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.41.tpd @@ -0,0 +1,8 @@ +target "jgit-4.41" with source configurePhase + +include "orbit/orbit-4.41.tpd" +include "maven/dependencies.tpd" + +location "https://download.eclipse.org/staging/2026-09/" { + 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 b67fa77a86c..1aa1518bc62 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.20.0" + version = "1.22.1" } dependency { groupId = "org.apache.commons" @@ -25,12 +25,12 @@ maven apache dependency { groupId = "commons-io" artifactId = "commons-io" - version = "2.21.0" + version = "2.22.0" } dependency { groupId = "commons-logging" artifactId = "commons-logging" - version = "1.3.5" + version = "1.4.0" } } @@ -69,22 +69,22 @@ maven bouncycastle dependency { groupId = "org.bouncycastle" artifactId = "bcpg-jdk18on" - version = "1.83" + version = "1.85" } dependency { groupId = "org.bouncycastle" artifactId = "bcprov-jdk18on" - version = "1.83" + version = "1.85" } dependency { groupId = "org.bouncycastle" artifactId = "bcpkix-jdk18on" - version = "1.83" + version = "1.85" } dependency { groupId = "org.bouncycastle" artifactId = "bcutil-jdk18on" - version = "1.83" + version = "1.85" } } @@ -97,12 +97,12 @@ maven bytebuddy dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy" - version = "1.18.4" + version = "1.18.11" } dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy-agent" - version = "1.18.4" + version = "1.18.11" } } @@ -115,7 +115,7 @@ maven gson dependency { groupId = "com.google.code.gson" artifactId = "gson" - version = "2.13.2" + version = "2.14.0" } } @@ -152,44 +152,44 @@ maven jetty includeSources { dependency { - groupId = "org.eclipse.jetty.ee10" - artifactId = "jetty-ee10-servlet" - version = "12.1.5" + groupId = "org.eclipse.jetty.ee11" + artifactId = "jetty-ee11-servlet" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-http" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-io" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-security" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-server" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-session" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util-ajax" - version = "12.1.5" + version = "12.1.11" } dependency { groupId = "jakarta.servlet" @@ -207,12 +207,12 @@ maven jna dependency { groupId = "net.java.dev.jna" artifactId = "jna" - version = "5.18.1" + version = "5.19.1" } dependency { groupId = "net.java.dev.jna" artifactId = "jna-platform" - version = "5.18.1" + version = "5.19.1" } } @@ -225,7 +225,7 @@ maven mockito dependency { groupId = "org.mockito" artifactId = "mockito-core" - version = "5.21.0" + version = "5.23.0" } } @@ -238,12 +238,12 @@ maven sshd dependency { groupId = "org.apache.sshd" artifactId = "sshd-osgi" - version = "2.17.1" + version = "2.19.0" } dependency { groupId = "org.apache.sshd" artifactId = "sshd-sftp" - version = "2.17.1" + version = "2.19.0" } } @@ -256,12 +256,17 @@ maven slf4j dependency { groupId = "org.slf4j" artifactId = "slf4j-api" - version = "2.0.17" + version = "2.0.18" } dependency { groupId = "org.slf4j" artifactId = "slf4j-simple" - version = "2.0.17" + version = "2.0.18" + } + dependency { + groupId = "org.slf4j" + artifactId = "jcl-over-slf4j" + version = "2.0.18" } } @@ -274,6 +279,6 @@ maven xz dependency { groupId = "org.tukaani" artifactId = "xz" - version = "1.11" + version = "1.12" } } \ No newline at end of file diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd index 48725cafb07..54f77894741 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.39.tpd @@ -22,8 +22,8 @@ location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026 org.objectweb.asm.util [9.9.1,9.9.1] org.objectweb.asm.tree [9.9.1,9.9.1] org.objectweb.asm.tree.analysis [9.9.1,9.9.1] - org.objenesis [3.4,3.4] - org.objenesis.source [3.4,3.4] + org.objenesis [3.5.0,3.5.0] + org.objenesis.source [3.5.0,3.5.0] 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.40.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.40.tpd new file mode 100644 index 00000000000..4ce74f7c696 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.40.tpd @@ -0,0 +1,29 @@ +target "orbit-4.40" with source configurePhase +// see https://download.eclipse.org/tools/orbit/downloads/ + +location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026-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] + org.apache.ant [1.10.17.v20260410-1000,1.10.17.v20260410-1000] + org.apache.ant.source [1.10.17.v20260410-1000,1.10.17.v20260410-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] + 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 [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] + 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.objectweb.asm [9.9.1,9.9.1] + org.objectweb.asm.commons [9.9.1,9.9.1] + org.objectweb.asm.util [9.9.1,9.9.1] + org.objectweb.asm.tree [9.9.1,9.9.1] + org.objectweb.asm.tree.analysis [9.9.1,9.9.1] + org.objenesis [3.5.0,3.5.0] + org.objenesis.source [3.5.0,3.5.0] + 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.41.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.41.tpd new file mode 100644 index 00000000000..f38ad9452e8 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.41.tpd @@ -0,0 +1,29 @@ +target "orbit-4.41" with source configurePhase +// see https://download.eclipse.org/tools/orbit/downloads/ + +location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026-09" { + com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] + com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] + com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] + com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] + org.apache.ant [1.10.17.v20260410-1000,1.10.17.v20260410-1000] + org.apache.ant.source [1.10.17.v20260410-1000,1.10.17.v20260410-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] + 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 [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] + 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.objectweb.asm [9.10.1,9.10.1] + org.objectweb.asm.commons [9.10.1,9.10.1] + org.objectweb.asm.util [9.10.1,9.10.1] + org.objectweb.asm.tree [9.10.1,9.10.1] + org.objectweb.asm.tree.analysis [9.10.1,9.10.1] + org.objenesis [3.5.0,3.5.0] + org.objenesis.source [3.5.0,3.5.0] + 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 07f6f21f45f..a31b9288d90 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml @@ -16,7 +16,7 @@ org.eclipse.jgit jgit.tycho.parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT pom JGit Tycho Parent diff --git a/org.eclipse.jgit.pgm.test/BUILD b/org.eclipse.jgit.pgm.test/BUILD index b8ffa695940..fdd87d3e95e 100644 --- a/org.eclipse.jgit.pgm.test/BUILD +++ b/org.eclipse.jgit.pgm.test/BUILD @@ -15,8 +15,8 @@ junit_tests( deps = [ ":helpers", "//lib:args4j", - "//lib:commons-io", "//lib:commons-compress", + "//lib:commons-io", "//lib:javaewah", "//lib:junit", "//lib:slf4j-api", diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF index 5f81b7d60d7..a28a4efb467 100644 --- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF @@ -3,31 +3,31 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm.test Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: org.eclipse.jgit.api;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.diff;version="[7.6.0,7.7.0)", - org.eclipse.jgit.dircache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.merge;version="[7.6.0,7.7.0)", - org.eclipse.jgit.pgm;version="[7.6.0,7.7.0)", - org.eclipse.jgit.pgm.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.pgm.opt;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.io;version="[7.6.0,7.7.0)", +Import-Package: org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.diff;version="[7.8.0,7.9.0)", + org.eclipse.jgit.dircache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.merge;version="[7.8.0,7.9.0)", + org.eclipse.jgit.pgm;version="[7.8.0,7.9.0)", + org.eclipse.jgit.pgm.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.pgm.opt;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.io;version="[7.8.0,7.9.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 de0a37aa8a6..5319d3e79b5 100644 --- a/org.eclipse.jgit.pgm.test/pom.xml +++ b/org.eclipse.jgit.pgm.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.pgm.test diff --git a/org.eclipse.jgit.pgm/BUILD b/org.eclipse.jgit.pgm/BUILD index a267b155ac9..596aed2e24b 100644 --- a/org.eclipse.jgit.pgm/BUILD +++ b/org.eclipse.jgit.pgm/BUILD @@ -16,13 +16,13 @@ java_library( "//lib:commons-logging", "//lib:httpclient", "//lib:httpcore", + "//lib:jakarta-servlet-api", "//lib:jetty-http", "//lib:jetty-io", "//lib:jetty-security", "//lib:jetty-server", "//lib:jetty-servlet", "//lib:jetty-util", - "//lib:servlet-api", "//org.eclipse.jgit.archive:jgit-archive", "//org.eclipse.jgit.http.apache:http-apache", "//org.eclipse.jgit:jgit", diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF index 0e19ea5ff81..83dc25ad146 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF @@ -3,62 +3,62 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", +Import-Package: jakarta.servlet;version="[6.1.0,7.0.0)", org.apache.commons.logging;version="[1.2,2.0)", - org.eclipse.jetty.ee10.servlet;version="[12.0.0,13.0.0)", + org.eclipse.jetty.ee11.servlet;version="[12.0.0,13.0.0)", org.eclipse.jetty.server;version="[12.0.0,13.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.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.archive;version="[7.6.0,7.7.0)", - org.eclipse.jgit.awtui;version="[7.6.0,7.7.0)", - org.eclipse.jgit.blame;version="[7.6.0,7.7.0)", - org.eclipse.jgit.diff;version="[7.6.0,7.7.0)", - org.eclipse.jgit.dircache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.gitrepo;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.io;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.midx;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.server;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.server.fs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs.server.s3;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.merge;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.notes;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revplot;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http.apache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.resolver;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.ssh.jsch;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.sshd;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.io;version="[7.6.0,7.7.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.archive;version="[7.8.0,7.9.0)", + org.eclipse.jgit.awtui;version="[7.8.0,7.9.0)", + org.eclipse.jgit.blame;version="[7.8.0,7.9.0)", + org.eclipse.jgit.diff;version="[7.8.0,7.9.0)", + org.eclipse.jgit.dircache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.gitrepo;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.io;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.midx;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.server;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.server.fs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs.server.s3;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.merge;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.notes;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revplot;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http.apache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.resolver;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.ssh.jsch;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.sshd;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.io;version="[7.8.0,7.9.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.6.0"; +Export-Package: org.eclipse.jgit.console;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util", - org.eclipse.jgit.pgm;version="7.6.0"; + org.eclipse.jgit.pgm;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util.io, org.eclipse.jgit.awtui, @@ -70,14 +70,14 @@ Export-Package: org.eclipse.jgit.console;version="7.6.0"; org.eclipse.jgit.treewalk, org.eclipse.jgit.api, javax.swing", - org.eclipse.jgit.pgm.debug;version="7.6.0"; + org.eclipse.jgit.pgm.debug;version="7.8.0"; uses:="org.eclipse.jgit.util.io, org.eclipse.jgit.pgm, org.eclipse.jetty.servlet", - org.eclipse.jgit.pgm.internal;version="7.6.0"; + org.eclipse.jgit.pgm.internal;version="7.8.0"; x-friends:="org.eclipse.jgit.pgm.test, org.eclipse.jgit.test", - org.eclipse.jgit.pgm.opt;version="7.6.0"; + org.eclipse.jgit.pgm.opt;version="7.8.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 dcb551955e6..e9a6b049971 100644 --- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index 041c46db7c5..042033d8c42 100644 --- a/org.eclipse.jgit.pgm/pom.xml +++ b/org.eclipse.jgit.pgm/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.pgm @@ -107,8 +107,8 @@ - org.eclipse.jetty.ee10 - jetty-ee10-servlet + org.eclipse.jetty.ee11 + jetty-ee11-servlet 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 index a7df4faa29c..37e835a5e60 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java @@ -13,19 +13,15 @@ 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.LinkedHashMap; +import java.util.regex.Pattern; +import org.eclipse.jgit.internal.storage.file.MidxWriter; 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.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.storage.pack.PackConfig; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @@ -38,6 +34,9 @@ class MultiPackIndex extends TextBuiltin { @Option(name = "--midx") private String midxPath; + @Option(name = "--bitmaps") + private boolean writeBitmaps; + /** {@inheritDoc} */ @Override protected void run() throws IOException { @@ -74,6 +73,11 @@ private void writeMultiPackIndex() throws IOException { throw die("This repository object db doesn't have packs"); } + ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); + if (hasLooseObjects(odb)) { + throw die("Cannot write multi-pack-index with loose objects"); + } + File midx; if (midxPath == null || midxPath.isEmpty()) { midx = new File(((ObjectDirectory) db.getObjectDatabase()) @@ -83,24 +87,53 @@ private void writeMultiPackIndex() throws IOException { } errw.println("Writing " + midx.getAbsolutePath()); + PackConfig packConfig = null; + if (writeBitmaps) { + packConfig = new PackConfig(); + packConfig.setBitmapRecentCommitSpan(1); + packConfig.setBitmapRecentCommitSpan(100); + } - ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); + MidxWriter.writeMidx(new TextProgressMonitor(errw), db, odb.getPacks(), + midx, packConfig); + } - LinkedHashMap indexes = new LinkedHashMap<>(); - 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); - } + private static final Pattern FANOUT_DIR_PATTERN = Pattern + .compile("^[0-9a-f]{2}$"); + + /** + * Checks if the repository's object directory contains any loose objects. + * + * @param objDir + * the ObjectDirectory to check. + * @return {@code true} if any loose objects are found, {@code false} + * otherwise. + */ + private static boolean hasLooseObjects(ObjectDirectory objDir) { + File objectsDir = objDir.getDirectory(); + if (objectsDir == null || !objectsDir.isDirectory()) { + return false; } - 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); + String[] fanoutDirNames = objectsDir.list(); + if (fanoutDirNames == null) { + return false; } + + for (String dirName : fanoutDirNames) { + if (FANOUT_DIR_PATTERN.matcher(dirName).matches()) { + File fanoutDir = new File(objectsDir, dirName); + if (fanoutDir.isDirectory()) { + String[] objects = fanoutDir.list(); + // If the fan-out directory is not empty, we have loose + // objects. + if (objects != null && objects.length > 0) { + return true; + } + } + } + } + + return false; } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java index 757c4357228..fa40431118f 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/LfsStore.java @@ -26,8 +26,8 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.ee10.servlet.ServletContextHandler; -import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee11.servlet.ServletContextHandler; +import org.eclipse.jetty.ee11.servlet.ServletHolder; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lfs.server.LargeFileRepository; import org.eclipse.jgit.lfs.server.LfsProtocolServlet; 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 2ef72566aa4..35e15336296 100644 --- a/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.agent/META-INF/MANIFEST.MF @@ -2,17 +2,18 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.agent;singleton:=true -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/agent Bundle-Vendor: %Bundle-Vendor -Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[7.6.0,7.7.0)" +Fragment-Host: org.eclipse.jgit.ssh.apache;bundle-version="[7.8.0,7.9.0)" Bundle-ActivationPolicy: lazy Automatic-Module-Name: org.eclipse.jgit.ssh.apache.agent Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: org.eclipse.jgit.transport.sshd;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)" +Import-Package: org.eclipse.jgit.transport.sshd;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.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.6.0";x-internal:=true +Export-Package: org.eclipse.jgit.internal.transport.sshd.agent.connector;version="7.8.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 56d463f7f96..9a8ae16ca80 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,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache.agent;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.apache.agent/pom.xml b/org.eclipse.jgit.ssh.apache.agent/pom.xml index 9c2bf0345c7..8769f646466 100644 --- a/org.eclipse.jgit.ssh.apache.agent/pom.xml +++ b/org.eclipse.jgit.ssh.apache.agent/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ssh.apache.agent diff --git a/org.eclipse.jgit.ssh.apache.test/BUILD b/org.eclipse.jgit.ssh.apache.test/BUILD index bf796c058e3..e36f8d60bb4 100644 --- a/org.eclipse.jgit.ssh.apache.test/BUILD +++ b/org.eclipse.jgit.ssh.apache.test/BUILD @@ -6,6 +6,7 @@ load( "@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests", ) +load("@rules_java//java:defs.bzl", "java_library") DEPS = [ "//lib:bcpkix", 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 d2bf5aeb258..8bef119bebb 100644 --- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF @@ -3,45 +3,45 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Import-Package: org.apache.sshd.agent;version="[2.17.1,2.18.0)", - org.apache.sshd.certificate;version="[2.17.1,2.18.0)", - org.apache.sshd.client.config.hosts;version="[2.17.1,2.18.0)", - org.apache.sshd.common;version="[2.17.1,2.18.0)", - org.apache.sshd.common.auth;version="[2.17.1,2.18.0)", - org.apache.sshd.common.cipher;version="[2.17.1,2.18.0)", - org.apache.sshd.common.config.keys;version="[2.17.1,2.18.0)", - org.apache.sshd.common.helpers;version="[2.17.1,2.18.0)", - org.apache.sshd.common.kex;version="[2.17.1,2.18.0)", - org.apache.sshd.common.keyprovider;version="[2.17.1,2.18.0)", - org.apache.sshd.common.session;version="[2.17.1,2.18.0)", - org.apache.sshd.common.signature;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.buffer;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.net;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.security;version="[2.17.1,2.18.0)", - org.apache.sshd.core;version="[2.17.1,2.18.0)", - org.apache.sshd.server;version="[2.17.1,2.18.0)", - org.apache.sshd.server.forward;version="[2.17.1,2.18.0)", - org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.signing.ssh;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.sshd;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.sshd.proxy;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit.ssh;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.sshd;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.sshd.agent;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", +Import-Package: org.apache.sshd.agent;version="[2.19.0,3.0.0)", + org.apache.sshd.certificate;version="[2.19.0,3.0.0)", + org.apache.sshd.client.config.hosts;version="[2.19.0,3.0.0)", + org.apache.sshd.common;version="[2.19.0,3.0.0)", + org.apache.sshd.common.auth;version="[2.19.0,3.0.0)", + org.apache.sshd.common.cipher;version="[2.19.0,3.0.0)", + org.apache.sshd.common.config.keys;version="[2.19.0,3.0.0)", + org.apache.sshd.common.helpers;version="[2.19.0,3.0.0)", + org.apache.sshd.common.kex;version="[2.19.0,3.0.0)", + org.apache.sshd.common.keyprovider;version="[2.19.0,3.0.0)", + org.apache.sshd.common.session;version="[2.19.0,3.0.0)", + org.apache.sshd.common.signature;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.buffer;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.net;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.security;version="[2.19.0,3.0.0]", + org.apache.sshd.core;version="[2.19.0,3.0.0)", + org.apache.sshd.server;version="[2.19.0,3.0.0)", + org.apache.sshd.server.forward;version="[2.19.0,3.0.0)", + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.signing.ssh;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.sshd;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.sshd.proxy;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit.ssh;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.sshd;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.sshd.agent;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml index 5a9057fe5cd..c42eb2bea1d 100644 --- a/org.eclipse.jgit.ssh.apache.test/pom.xml +++ b/org.eclipse.jgit.ssh.apache.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ssh.apache.test 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 index 6b61821a0f1..ff6eb2badc6 100644 --- 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 @@ -28,6 +28,7 @@ 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.OpenSshCertificate; import org.apache.sshd.common.config.keys.PublicKeyEntry; import org.apache.sshd.common.util.security.SecurityUtils; import org.eclipse.jgit.annotations.NonNull; @@ -58,7 +59,8 @@ public class OpenSshServerKeyDatabaseTest { private static PublicKey ec256; private static PublicKey ec384; private static PublicKey caKey; - private static PublicKey certificate; + + private static OpenSshCertificate certificate; @BeforeClass public static void initKeys() throws Exception { @@ -179,7 +181,7 @@ public void testCaKeyNotConsidered() throws Exception { } @Test - public void testkeyPlainAndCa() throws Exception { + public void testKeyPlainAndCa() throws Exception { Files.write(knownHosts, List.of( "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), "some.other.com " + PublicKeyEntry.toString(ec384), @@ -191,8 +193,47 @@ public void testkeyPlainAndCa() throws Exception { new KnownHostsConfig(), null)); } + @Test + public void testCaIsPlain() throws Exception { + Files.write(knownHosts, List.of( + "localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384), + "localhost,127.0.0.1 " + PublicKeyEntry.toString(caKey))); + // caKey not marked as cert-authorithy + assertFalse(database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig(), null)); + } + + @Test + public void testRevokedCa() throws Exception { + Files.write(knownHosts, + List.of("localhost,127.0.0.1 " + + PublicKeyEntry.toString(rsa1024), + "some.other.com " + PublicKeyEntry.toString(ec384), + "@revoked localhost,127.0.0.1 " + + PublicKeyEntry.toString(caKey))); + assertFalse(database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig(), null)); + } + + @Test + public void testRevokedCertifiedKey() 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), + "@revoked localhost,127.0.0.1 " + PublicKeyEntry + .toString(certificate.getCertPubKey()))); + assertFalse(database.accept("localhost", LOCAL, certificate, + new KnownHostsConfig(), null)); + } + @Test public void testLookupCertificate() throws Exception { + Files.write(knownHosts, List.of("@cert-authority localhost,127.0.0.1 " + + PublicKeyEntry.toString(caKey))); List keys = database.lookup("localhost", LOCAL, new KnownHostsConfig()); // Certificates or CA keys are not reported via lookup. diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF index 7a7d7e1b84f..37f2ab96433 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF @@ -6,11 +6,11 @@ Bundle-SymbolicName: org.eclipse.jgit.ssh.apache Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/plugin Bundle-ActivationPolicy: lazy -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.6.0";x-friends:="org.eclipse.jgit.ssh.apache.test", - org.eclipse.jgit.internal.transport.sshd;version="7.6.0";x-friends:="org.eclipse.jgit.ssh.apache.test"; +Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.8.0";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.internal.transport.sshd;version="7.8.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, @@ -25,80 +25,80 @@ Export-Package: org.eclipse.jgit.internal.signing.ssh;version="7.6.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.6.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.auth;version="7.6.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.pkcs11;version="7.6.0";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.proxy;version="7.6.0";x-friends:="org.eclipse.jgit.ssh.apache.test", - org.eclipse.jgit.signing.ssh;version="7.6.0";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.transport.sshd;version="7.6.0"; + org.eclipse.jgit.internal.transport.sshd.agent;version="7.8.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.auth;version="7.8.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.pkcs11;version="7.8.0";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.proxy;version="7.8.0";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.signing.ssh;version="7.8.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.transport.sshd;version="7.8.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.6.0" -Import-Package: org.bouncycastle.jce.provider;version="[1.80.0,2.0.0)", - org.apache.sshd.agent;version="[2.17.1,2.18.0)", - org.apache.sshd.client;version="[2.17.1,2.18.0)", - org.apache.sshd.client.auth;version="[2.17.1,2.18.0)", - org.apache.sshd.client.auth.keyboard;version="[2.17.1,2.18.0)", - org.apache.sshd.client.auth.password;version="[2.17.1,2.18.0)", - org.apache.sshd.client.auth.pubkey;version="[2.17.1,2.18.0)", - org.apache.sshd.client.channel;version="[2.17.1,2.18.0)", - org.apache.sshd.client.config.hosts;version="[2.17.1,2.18.0)", - org.apache.sshd.client.config.keys;version="[2.17.1,2.18.0)", - org.apache.sshd.client.future;version="[2.17.1,2.18.0)", - org.apache.sshd.client.keyverifier;version="[2.17.1,2.18.0)", - org.apache.sshd.client.session;version="[2.17.1,2.18.0)", - org.apache.sshd.client.session.forward;version="[2.17.1,2.18.0)", - org.apache.sshd.common;version="[2.17.1,2.18.0)", - org.apache.sshd.common.auth;version="[2.17.1,2.18.0)", - org.apache.sshd.common.channel;version="[2.17.1,2.18.0)", - org.apache.sshd.common.cipher;version="[2.17.1,2.18.0)", - org.apache.sshd.common.compression;version="[2.17.1,2.18.0)", - org.apache.sshd.common.config.keys;version="[2.17.1,2.18.0)", - org.apache.sshd.common.config.keys.loader;version="[2.17.1,2.18.0)", - org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.17.1,2.18.0)", - org.apache.sshd.common.config.keys.u2f;version="[2.17.1,2.18.0)", - org.apache.sshd.common.digest;version="[2.17.1,2.18.0)", - org.apache.sshd.common.forward;version="[2.17.1,2.18.0)", - org.apache.sshd.common.future;version="[2.17.1,2.18.0)", - org.apache.sshd.common.helpers;version="[2.17.1,2.18.0)", - org.apache.sshd.common.io;version="[2.17.1,2.18.0)", - org.apache.sshd.common.kex;version="[2.17.1,2.18.0)", - org.apache.sshd.common.kex.extension;version="[2.17.1,2.18.0)", - org.apache.sshd.common.kex.extension.parser;version="[2.17.1,2.18.0)", - org.apache.sshd.common.keyprovider;version="[2.17.1,2.18.0)", - org.apache.sshd.common.mac;version="[2.17.1,2.18.0)", - org.apache.sshd.common.random;version="[2.17.1,2.18.0)", - org.apache.sshd.common.session;version="[2.17.1,2.18.0)", - org.apache.sshd.common.session.helpers;version="[2.17.1,2.18.0)", - org.apache.sshd.common.signature;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.buffer;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.buffer.keys;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.closeable;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.io;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.io.der;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.io.functors;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.io.resource;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.logging;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.net;version="[2.17.1,2.18.0)", - org.apache.sshd.common.util.security;version="[2.17.1,2.18.0)", - org.apache.sshd.core;version="[2.17.1,2.18.0)", - org.apache.sshd.server.auth;version="[2.17.1,2.18.0)", - org.apache.sshd.sftp;version="[2.17.1,2.18.0)", - org.apache.sshd.sftp.client;version="[2.17.1,2.18.0)", - org.apache.sshd.sftp.common;version="[2.17.1,2.18.0)", - org.eclipse.jgit.annotations;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.fnmatch;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.transport.sshd.agent;version="7.8.0" +Import-Package: org.bouncycastle.jce.provider;version="[1.84.0,2.0.0)", + org.apache.sshd.agent;version="[2.19.0,3.0.0)", + org.apache.sshd.client;version="[2.19.0,3.0.0)", + org.apache.sshd.client.auth;version="[2.19.0,3.0.0)", + org.apache.sshd.client.auth.keyboard;version="[2.19.0,3.0.0)", + org.apache.sshd.client.auth.password;version="[2.19.0,3.0.0)", + org.apache.sshd.client.auth.pubkey;version="[2.19.0,3.0.0)", + org.apache.sshd.client.channel;version="[2.19.0,3.0.0)", + org.apache.sshd.client.config.hosts;version="[2.19.0,3.0.0)", + org.apache.sshd.client.config.keys;version="[2.19.0,3.0.0)", + org.apache.sshd.client.future;version="[2.19.0,3.0.0)", + org.apache.sshd.client.keyverifier;version="[2.19.0,3.0.0)", + org.apache.sshd.client.session;version="[2.19.0,3.0.0)", + org.apache.sshd.client.session.forward;version="[2.19.0,3.0.0)", + org.apache.sshd.common;version="[2.19.0,3.0.0)", + org.apache.sshd.common.auth;version="[2.19.0,3.0.0)", + org.apache.sshd.common.channel;version="[2.19.0,3.0.0)", + org.apache.sshd.common.cipher;version="[2.19.0,3.0.0)", + org.apache.sshd.common.compression;version="[2.19.0,3.0.0)", + org.apache.sshd.common.config.keys;version="[2.19.0,3.0.0)", + org.apache.sshd.common.config.keys.loader;version="[2.19.0,3.0.0)", + org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.19.0,3.0.0)", + org.apache.sshd.common.config.keys.u2f;version="[2.19.0,3.0.0)", + org.apache.sshd.common.digest;version="[2.19.0,3.0.0)", + org.apache.sshd.common.forward;version="[2.19.0,3.0.0)", + org.apache.sshd.common.future;version="[2.19.0,3.0.0)", + org.apache.sshd.common.helpers;version="[2.19.0,3.0.0)", + org.apache.sshd.common.io;version="[2.19.0,3.0.0)", + org.apache.sshd.common.kex;version="[2.19.0,3.0.0)", + org.apache.sshd.common.kex.extension;version="[2.19.0,3.0.0)", + org.apache.sshd.common.kex.extension.parser;version="[2.19.0,3.0.0)", + org.apache.sshd.common.keyprovider;version="[2.19.0,3.0.0)", + org.apache.sshd.common.mac;version="[2.19.0,3.0.0)", + org.apache.sshd.common.random;version="[2.19.0,3.0.0)", + org.apache.sshd.common.session;version="[2.19.0,3.0.0)", + org.apache.sshd.common.session.helpers;version="[2.19.0,3.0.0)", + org.apache.sshd.common.signature;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.buffer;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.buffer.keys;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.closeable;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.io;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.io.der;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.io.functors;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.io.resource;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.logging;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.net;version="[2.19.0,3.0.0)", + org.apache.sshd.common.util.security;version="[2.19.0,3.0.0)", + org.apache.sshd.core;version="[2.19.0,3.0.0)", + org.apache.sshd.server.auth;version="[2.19.0,3.0.0)", + org.apache.sshd.sftp;version="[2.19.0,3.0.0)", + org.apache.sshd.sftp.client;version="[2.19.0,3.0.0)", + org.apache.sshd.sftp.common;version="[2.19.0,3.0.0)", + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.fnmatch;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.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 5ef864b3899..3b936a8cf8f 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml index 3edf6e6ce65..d5cff8da7fa 100644 --- a/org.eclipse.jgit.ssh.apache/pom.xml +++ b/org.eclipse.jgit.ssh.apache/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ssh.apache 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 acb77c5bb76..7300a44fb8e 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 @@ -210,10 +210,26 @@ public boolean accept(@NonNull String connectAddress, @NonNull Configuration config, CredentialsProvider provider) { List filesToUse = getFilesToUse(config); AskUser ask = new AskUser(config, provider); - HostEntryPair[] modified = { null }; - Path path = null; Collection candidates = getCandidates(connectAddress, remoteAddress); + if (acceptKey(remoteAddress, candidates, serverKey, filesToUse, config, + ask)) { + if (serverKey instanceof OpenSshCertificate certificate) { + if (isRevoked(remoteAddress, candidates, filesToUse, + certificate.getCertPubKey(), ask)) { + return false; + } + } + return true; + } + return false; + } + + private boolean acceptKey(InetSocketAddress remoteAddress, + Collection candidates, PublicKey serverKey, + List filesToUse, Configuration config, AskUser ask) { + HostEntryPair[] modified = { null }; + Path path = null; for (HostKeyFile file : filesToUse) { HostEntryPair lastModified = modified[0]; try { @@ -285,7 +301,26 @@ private static boolean isCertificateAuthority(KnownHostEntry entry) { return MARKER_CA.equals(entry.getMarker()); } - private boolean find(Collection candidates, + private static boolean isRevoked(InetSocketAddress remoteAddress, + Collection candidates, + List filesToUse, PublicKey serverKey, AskUser ask) { + HostEntryPair[] dummy = { null }; + for (HostKeyFile file : filesToUse) { + try { + if (find(candidates, serverKey, file.get(), dummy)) { + // It's definitely not revoked. + return false; + } + } catch (RevokedKeyException e) { + ask.revokedKey(remoteAddress, serverKey, file.getPath()); + return true; + } + } + // Not found, so it is not revoked + return false; + } + + private static boolean find(Collection candidates, PublicKey serverKey, List entries, HostEntryPair[] modified) throws RevokedKeyException { PublicKey keyToCheck = serverKey; 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 4632a36b0bf..85d12abdf26 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git Import-Package: com.jcraft.jsch;version="[0.1.54,0.2.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit.ssh;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.ssh.jsch;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit.ssh;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.ssh.jsch;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", diff --git a/org.eclipse.jgit.ssh.jsch.test/pom.xml b/org.eclipse.jgit.ssh.jsch.test/pom.xml index 70b0af03255..a5e57f69f60 100644 --- a/org.eclipse.jgit.ssh.jsch.test/pom.xml +++ b/org.eclipse.jgit.ssh.jsch.test/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ssh.jsch.test diff --git a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF index 436d2510170..8eaf94dbf78 100644 --- a/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch/META-INF/MANIFEST.MF @@ -3,20 +3,20 @@ 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.6.0,7.7.0)" +Fragment-Host: org.eclipse.jgit;bundle-version="[7.8.0,7.9.0)" Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/jsch Bundle-ActivationPolicy: lazy -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="7.6.0" +Export-Package: org.eclipse.jgit.transport.ssh.jsch;version="7.8.0" Import-Package: com.jcraft.jsch;version="[0.1.37,0.2.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.io;version="[7.6.0,7.7.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.io;version="[7.8.0,7.9.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 7cba3294642..9d08701fc5e 100644 --- a/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.ssh.jsch;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.jsch/pom.xml b/org.eclipse.jgit.ssh.jsch/pom.xml index 91caa5e818e..865298d9ecc 100644 --- a/org.eclipse.jgit.ssh.jsch/pom.xml +++ b/org.eclipse.jgit.ssh.jsch/pom.xml @@ -17,7 +17,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ssh.jsch diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD index 7755df04996..a3765da1b67 100644 --- a/org.eclipse.jgit.test/BUILD +++ b/org.eclipse.jgit.test/BUILD @@ -24,6 +24,7 @@ HELPERS = glob( "nls/MissingPropertyBundle.java", "nls/NoPropertiesBundle.java", "nls/NonTranslatedBundle.java", + "revwalk/AbstractRevWalkWithCommitGraphTest.java", "revwalk/RevQueueTestCase.java", "revwalk/RevWalkTestCase.java", "transport/ObjectIdMatcher.java", @@ -53,10 +54,11 @@ tests(tests = glob( exclude = HELPERS + DATA + EXCLUDED, )) - -tests(tests = glob(["exttst/**/*.java"]), +tests( + extra_tags = ["ext"], srcprefix = "exttst/", - extra_tags = ["ext"]) + tests = glob(["exttst/**/*.java"]), +) # Non abstract base classes used for tests by other test classes BASE = [ diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index bee0f4927ee..5cab045aa0e 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 @@ -21,66 +21,66 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.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.6.0,7.7.0)", - org.eclipse.jgit.api;version="[7.6.0,7.7.0)", - org.eclipse.jgit.api.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.archive;version="[7.6.0,7.7.0)", - org.eclipse.jgit.attributes;version="[7.6.0,7.7.0)", - org.eclipse.jgit.awtui;version="[7.6.0,7.7.0)", - org.eclipse.jgit.blame;version="[7.6.0,7.7.0)", - org.eclipse.jgit.blame.cache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.diff;version="[7.6.0,7.7.0)", - org.eclipse.jgit.dircache;version="[7.6.0,7.7.0)", - org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.events;version="[7.6.0,7.7.0)", - org.eclipse.jgit.fnmatch;version="[7.6.0,7.7.0)", - org.eclipse.jgit.gitrepo;version="[7.6.0,7.7.0)", - org.eclipse.jgit.hooks;version="[7.6.0,7.7.0)", - org.eclipse.jgit.ignore;version="[7.6.0,7.7.0)", - org.eclipse.jgit.ignore.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.diff;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.diffmergetool;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.fsck;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.commitgraph;version="7.6.0", - org.eclipse.jgit.internal.storage.dfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.io;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.memory;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.midx;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.storage.reftable;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.connectivity;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.parser;version="[7.6.0,7.7.0)", - org.eclipse.jgit.internal.transport.ssh;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit;version="[7.6.0,7.7.0)", - org.eclipse.jgit.junit.time;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lfs;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.logging;version="[7.6.0,7.7.0)", - org.eclipse.jgit.merge;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.notes;version="[7.6.0,7.7.0)", - org.eclipse.jgit.patch;version="[7.6.0,7.7.0)", - org.eclipse.jgit.pgm;version="[7.6.0,7.7.0)", - org.eclipse.jgit.pgm.internal;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revplot;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.file;version="[7.6.0,7.7.0)", - org.eclipse.jgit.storage.pack;version="[7.6.0,7.7.0)", - org.eclipse.jgit.submodule;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.http;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport.resolver;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.treewalk.filter;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.io;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util.sha1;version="[7.6.0,7.7.0)", + org.eclipse.jgit.annotations;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api;version="[7.8.0,7.9.0)", + org.eclipse.jgit.api.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.archive;version="[7.8.0,7.9.0)", + org.eclipse.jgit.attributes;version="[7.8.0,7.9.0)", + org.eclipse.jgit.awtui;version="[7.8.0,7.9.0)", + org.eclipse.jgit.blame;version="[7.8.0,7.9.0)", + org.eclipse.jgit.blame.cache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.diff;version="[7.8.0,7.9.0)", + org.eclipse.jgit.dircache;version="[7.8.0,7.9.0)", + org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.events;version="[7.8.0,7.9.0)", + org.eclipse.jgit.fnmatch;version="[7.8.0,7.9.0)", + org.eclipse.jgit.gitrepo;version="[7.8.0,7.9.0)", + org.eclipse.jgit.hooks;version="[7.8.0,7.9.0)", + org.eclipse.jgit.ignore;version="[7.8.0,7.9.0)", + org.eclipse.jgit.ignore.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.diff;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.diffmergetool;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.fsck;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.commitgraph;version="7.8.0", + org.eclipse.jgit.internal.storage.dfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.io;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.memory;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.midx;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.storage.reftable;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.connectivity;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.parser;version="[7.8.0,7.9.0)", + org.eclipse.jgit.internal.transport.ssh;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit;version="[7.8.0,7.9.0)", + org.eclipse.jgit.junit.time;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lfs;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.logging;version="[7.8.0,7.9.0)", + org.eclipse.jgit.merge;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.notes;version="[7.8.0,7.9.0)", + org.eclipse.jgit.patch;version="[7.8.0,7.9.0)", + org.eclipse.jgit.pgm;version="[7.8.0,7.9.0)", + org.eclipse.jgit.pgm.internal;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revplot;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.file;version="[7.8.0,7.9.0)", + org.eclipse.jgit.storage.pack;version="[7.8.0,7.9.0)", + org.eclipse.jgit.submodule;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.http;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport.resolver;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.treewalk.filter;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.io;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util.sha1;version="[7.8.0,7.9.0)", org.hamcrest;version="[3.0.0,4.0.0)", org.hamcrest.collection;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/midx/CgitMidxCompatibilityTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/midx/CgitMidxCompatibilityTest.java index 334e52b0423..3aa6d69b103 100644 --- 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 @@ -25,13 +25,10 @@ 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; @@ -93,15 +90,15 @@ public void jgit_loadsCgitMidx() } private byte[] generateJGitMidx() throws IOException { - Map indexes = new HashMap<>(); + PackIndexMerger.Builder builder = PackIndexMerger.builder(); for (Pack pack : db.getObjectDatabase().getPacks()) { PackFile packFile = pack.getPackFile().create(PackExt.INDEX); - indexes.put(packFile.getName(), pack.getIndex()); + builder.addPack(packFile.getName(), pack.getIndex()); } MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, indexes); + writer.write(NullProgressMonitor.INSTANCE, out, builder.build()); return out.toByteArray(); } diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index 387f1683069..531bdcbf065 100644 --- a/org.eclipse.jgit.test/pom.xml +++ b/org.eclipse.jgit.test/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.test diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java index c5210c895ff..e155f5d7187 100644 --- a/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java +++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/internal/storage/dfs/MidxTestUtils.java @@ -150,8 +150,12 @@ static DfsPackFileMidx writeMultipackIndex(DfsRepository db, Arrays.asList(packs), base != null ? base.getPackDescription() : null, packConfig); db.getObjectDatabase().commitPack(List.of(desc), null); + + // "packs" argument can have a midx and its base in the list. + List allPlainPacks = MidxPackList + .create(db.getObjectDatabase().getPacks()).getAllPlainPacks(); return DfsPackFileMidx.create(DfsBlockCache.getInstance(), desc, - Arrays.asList(packs), base); + allPlainPacks, base); } record CommitObjects(RevCommit commit, RevTree tree, RevBlob blob) { @@ -169,9 +173,7 @@ static List writeCommitChain(DfsRepository db, } try (TestRepository repository = new TestRepository<>( - (InMemoryRepository) db); - DfsInserter ins = (DfsInserter) db.getObjectDatabase() - .newInserter()) { + (InMemoryRepository) db)) { for (int i = 0; i < length; i++) { RevBlob blob = repository.blob("blob" + commitCounter); diff --git a/org.eclipse.jgit.test/tests.bzl b/org.eclipse.jgit.test/tests.bzl index 41f76d090ac..537ee8adee8 100644 --- a/org.eclipse.jgit.test/tests.bzl +++ b/org.eclipse.jgit.test/tests.bzl @@ -1,13 +1,14 @@ -''' +""" Expose each test as a bazel target -''' +""" + load( "@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests", ) -def tests(tests, srcprefix="tst/", extra_tags=[]): - ''' +def tests(tests, srcprefix = "tst/", extra_tags = []): + """ Create a target each of the tests Each target is the full push (removing srcprefix) replacing directory @@ -21,7 +22,7 @@ def tests(tests, srcprefix="tst/", extra_tags=[]): 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(srcprefix):len(src) - len(".java")].replace("/", "_") labels = [] @@ -72,6 +73,11 @@ def tests(tests, srcprefix="tst/", extra_tags=[]): "//lib:xz", "//org.eclipse.jgit.archive:jgit-archive", ] + if src.endswith("RevWalkSortTest.java") or \ + src.endswith("RevWalkSortTopoWithCommitGraphTest.java"): + additional_deps = [ + "//lib:assertj-core", + ] if src.endswith("FileRepositoryBuilderAfterOpenConfigTest.java") or \ src.endswith("RefDirectoryAfterOpenConfigTest.java") or \ src.endswith("SnapshottingRefDirectoryTest.java"): 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 226677229cc..0d87109fea4 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 @@ -27,6 +27,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.nio.file.Files; +import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -109,6 +110,46 @@ public void testAddExistingSingleFile() throws IOException, GitAPIException { } } + @Test + public void testAddExistingMultipleFiles() + throws IOException, GitAPIException { + File file = new File(db.getWorkTree(), "a.txt"); + FileUtils.createNewFile(file); + file = new File(db.getWorkTree(), "b.txt"); + FileUtils.createNewFile(file); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("content"); + } + + try (Git git = new Git(db)) { + git.add().addFilepatterns("a.txt", "b.txt").call(); + + assertEquals( + "[a.txt, mode:100644, content:][b.txt, mode:100644, content:content]", + indexState(CONTENT)); + } + } + + @Test + public void testAddExistingMultipleFilesCollection() + throws IOException, GitAPIException { + File file = new File(db.getWorkTree(), "a.txt"); + FileUtils.createNewFile(file); + file = new File(db.getWorkTree(), "b.txt"); + FileUtils.createNewFile(file); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("content"); + } + + try (Git git = new Git(db)) { + git.add().addFilepatterns(List.of("a.txt", "b.txt")).call(); + + assertEquals( + "[a.txt, mode:100644, content:][b.txt, mode:100644, content:content]", + indexState(CONTENT)); + } + } + @Test public void testAddLink() throws IOException, GitAPIException { assumeTrue(db.getFS().supportsSymlinks()); 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 3f5c5da55a1..cb91b121c64 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 @@ -11,6 +11,8 @@ import static org.eclipse.jgit.api.CherryPickCommitMessageProvider.ORIGINAL; import static org.eclipse.jgit.api.CherryPickCommitMessageProvider.ORIGINAL_WITH_REFERENCE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -22,6 +24,7 @@ import java.util.Iterator; import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; @@ -395,6 +398,23 @@ public void testCherryPickConflictMarkers() throws Exception { } } + @Test + public void testCherryPickConflictDiff3Markers() throws Exception { + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); + + db.getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()).call(); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + + String expected = "<<<<<<< master\na(master)\n||||||| BASE\na\n=======\na(side)\n>>>>>>> 527460a side\n"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } + } + @Test public void testCherryPickConflictFiresModifiedEvent() throws Exception { ListenerHandle listener = null; 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 1ec506798c4..086e2613867 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 @@ -10,6 +10,8 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.lib.Constants.MASTER; import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.junit.Assert.assertEquals; @@ -27,6 +29,7 @@ import java.util.Iterator; import java.util.regex.Pattern; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.ResetCommand.ResetType; @@ -2220,4 +2223,37 @@ private void checkMergeFailedResult(final MergeResult result, assertEquals(null, result.getConflicts()); assertEquals(RepositoryState.SAFE, db.getRepositoryState()); } + + @Test + public void testDiff3ConflictStyle() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + checkoutBranch("refs/heads/master"); + + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + db.getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + + assertEquals( + "1\n<<<<<<< HEAD\na(main)\n||||||| BASE\na\n=======\na(side)\n>>>>>>> d97aebf6e0bbdb3f21f8a22ec8cbf1ac24d986d8\n3\n", + read(new File(db.getWorkTree(), "a"))); + } + } } 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 695681de8dc..2dc77cf509b 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 @@ -10,6 +10,8 @@ package org.eclipse.jgit.api; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -25,6 +27,7 @@ import java.util.concurrent.Callable; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.junit.JGitTestUtil; @@ -162,6 +165,43 @@ public void testPullConflict() throws Exception { assertEquals(StageState.BOTH_MODIFIED, conflicting.get("SomeFile.txt")); } + @Test + public void testPullConflictDiff3() throws Exception { + PullResult res = target.pull().call(); + // nothing to update since we don't have different data yet + assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty()); + assertTrue(res.getMergeResult().getMergeStatus() + .equals(MergeStatus.ALREADY_UP_TO_DATE)); + + assertFileContentsEqual(targetFile, "Hello world"); + + // change the source file + writeToFile(sourceFile, "Source change"); + source.add().addFilepattern("SomeFile.txt").call(); + source.commit().setMessage("Source change in remote").call(); + + // change the target file + writeToFile(targetFile, "Target change"); + target.add().addFilepattern("SomeFile.txt").call(); + target.commit().setMessage("Target change in local").call(); + + target.getRepository().getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + res = target.pull().call(); + assertFalse(res.getFetchResult().getTrackingRefUpdates().isEmpty()); + assertTrue(res.getMergeResult().getMergeStatus() + .equals(MergeStatus.CONFLICTING)); + + String sourceChangeString = "Source change\n>>>>>>> branch 'master' of " + + target.getRepository().getConfig().getString("remote", + "origin", "url"); + + assertFileContentsEqual(targetFile, "<<<<<<< HEAD\n" + "Target change\n" + + "||||||| BASE\n" + "Hello world\n" + "=======\n" + + sourceChangeString + "\n"); + } + @Test public void testPullConflictTheirs() throws Exception { PullResult res = target.pull().call(); 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 4c8cf06a673..d99c2856455 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 @@ -10,6 +10,8 @@ package org.eclipse.jgit.api; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; @@ -30,6 +32,7 @@ import java.util.Iterator; import java.util.List; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler; import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler2; @@ -370,6 +373,43 @@ public void testRebaseNoMergeBaseConflict() throws Exception { + ">>>>>>> " + first.abbreviate(7).name() + " Add file\n"); } + /** + * Create a commit A and an unrelated commit B creating the same file with + * different content. Then rebase A onto B. The rebase should stop with a + * conflict and the conflict style should be DIFF3. + * + * @throws Exception on errors + */ + @Test + public void testRebaseNoMergeBaseConflictDiff3() throws Exception { + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + RevCommit first = git.commit().setMessage("Add file").call(); + File file1 = new File(db.getWorkTree(), FILE1); + assertTrue(file1.exists()); + // Create an independent branch + git.checkout().setOrphan(true).setName("orphan").call(); + git.rm().addFilepattern(FILE1).call(); + assertFalse(file1.exists()); + writeTrashFile(FILE1, "something else"); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Orphan").call(); + checkoutBranch("refs/heads/master"); + assertEquals(first.getId(), db.resolve("HEAD")); + + db.getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + RebaseResult res = git.rebase().setUpstream("refs/heads/orphan").call(); + assertEquals(Status.STOPPED, res.getStatus()); + assertEquals(first, res.getCurrentCommit()); + checkFile(file1, + "<<<<<<< Upstream, based on orphan\n" + "something else\n" + + "||||||| BASE\n" + "=======\n" + "file1\n" + + ">>>>>>> " + + first.abbreviate(7).name() + " Add file\n"); + } + /** * Create the following commits and then attempt to rebase topic onto * master. This will serialize the branches. 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 89fdb322204..a7a1dff8d1b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java @@ -9,6 +9,8 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -20,6 +22,7 @@ import java.io.IOException; import java.util.Iterator; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.errors.GitAPIException; @@ -376,6 +379,25 @@ public void testRevertConflictMarkers() throws Exception { } } + @Test + public void testRevertConflictMarkersDiff3() throws Exception { + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareRevert(git); + + db.getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + RevertCommand revert = git.revert(); + RevCommit newHead = revert.include(sideCommit.getId()).call(); + assertNull(newHead); + MergeResult result = revert.getFailingResult(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + + String expected = "<<<<<<< master\na(latest)\n||||||| BASE\na(previous)\n=======\na\n>>>>>>> ca96c31 second master\n"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } + } + @Test public void testRevertOurCommitName() throws Exception { try (Git git = new Git(db)) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java index 49b31b1c4c7..b169fac9483 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java @@ -9,15 +9,19 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.text.MessageFormat; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoHeadException; @@ -428,6 +432,43 @@ public void stashedContentMerge() throws Exception { read(PATH)); } + @Test + public void stashedContentMergeDiff3() throws Exception { + writeTrashFile(PATH, "content\nmore content\n"); + git.add().addFilepattern(PATH).call(); + git.commit().setMessage("more content").call(); + + writeTrashFile(PATH, "content\nhead change\nmore content\n"); + git.add().addFilepattern(PATH).call(); + git.commit().setMessage("even content").call(); + + writeTrashFile(PATH, "content\nstashed change\nmore content\n"); + + db.getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + RevCommit stashed = git.stashCreate().call(); + assertNotNull(stashed); + assertEquals("content\nhead change\nmore content\n", + read(committedFile)); + assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); + + writeTrashFile(PATH, "content\nmore content\ncommitted change\n"); + git.add().addFilepattern(PATH).call(); + git.commit().setMessage("committed change").call(); + recorder.assertNoEvent(); + + assertThrows(StashApplyFailureException.class, + () -> git.stashApply().call()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); + Status status = new StatusCommand(db).call(); + assertEquals(1, status.getConflicting().size()); + assertEquals( + "content\n<<<<<<< HEAD\n||||||| stashed HEAD\nhead change\n=======\nstashed change\n>>>>>>> stash\nmore content\ncommitted change\n", + read(PATH)); + } + @Test public void stashedContentMergeXtheirs() throws Exception { writeTrashFile(PATH, "content\nmore content\n"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java index 01d1e0282db..158d9deb696 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java @@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.MessageDigest; +import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -339,4 +340,29 @@ private static void copyMetaDataHelper(boolean keepStage) { assertTrue(e.isUpdateNeeded()); assertEquals("some/path", e.getPathString()); } + + @Test + public void testMightBeRacilyCleanNanoOverflow() { + DirCacheEntry entry = new DirCacheEntry("some/path"); + final Instant instant = Instant.ofEpochSecond(1, 999_999_999); + entry.setLastModified(instant.plus(Duration.ofNanos(1))); + assertTrue(entry.mightBeRacilyClean(instant)); + } + + @Test + public void testMightBeRacilyCleanOneSecondAfter() { + DirCacheEntry entry = new DirCacheEntry("some/path"); + final Instant instant = Instant.ofEpochSecond(1, 0); + entry.setLastModified(instant.plus(Duration.ofSeconds(1))); + assertTrue(entry.mightBeRacilyClean(instant)); + } + + @Test + public void testNotRacilyCleanWhenSmudgeIsAfter() { + DirCacheEntry entry = new DirCacheEntry("some/path"); + final Instant entryTime = Instant.ofEpochSecond(1, 0); + entry.setLastModified(entryTime); + final Instant smudge = entryTime.plus(Duration.ofNanos(1)); + assertFalse(entry.mightBeRacilyClean(smudge)); + } } 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 0949d040e91..d8ac28ceee6 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 @@ -254,4 +254,26 @@ public void testXXE() throws Exception { assertTrue(e.getCause().getMessage().contains("DOCTYPE")); } + @Test + public void testManifestParserWithReview() throws Exception { + String baseUrl = "https://git.google.com/"; + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("\n") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append(""); + + ManifestParser parser = new ManifestParser(null, null, "master", baseUrl, null, null); + parser.read(new ByteArrayInputStream(xmlContent.toString().getBytes(UTF_8))); + + Map map = parser.getProjects().stream() + .collect(Collectors.toMap(RepoProject::getPath, Function.identity())); + assertEquals("https://review-1.com", map.get("foo").getReview()); + assertEquals("https://review-2.com", map.get("bar").getReview()); + } + } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index 3162e7910b2..ceb18e65b6c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -1301,6 +1301,104 @@ public void testRecordSubmoduleLabels() throws Exception { } } + @Test + public void testRecordSubmoduleLabelsWithRemoteReview() throws Exception { + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("\n") + .append("") + .append( + "") + .append("") + .append("") + .append(""); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", xmlContent.toString()); + + RepoCommand command = new RepoCommand(remoteDb); + command + .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri) + .setRecordSubmoduleLabels(true) + .call(); + // Clone it + File directory = createTempDirectory("testBareRepo"); + try (Repository localDb = + Git.cloneRepository() + .setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()) + .call() + .getRepository(); ) { + // The .gitattributes file should exist + File gitattributes = new File(localDb.getWorkTree(), ".gitattributes"); + assertTrue("The .gitattributes file should exist", gitattributes.exists()); + try (BufferedReader reader = Files.newBufferedReader(gitattributes.toPath(), UTF_8)) { + String content = reader.readLine(); + assertEquals( + ".gitattributes content should be as expected", + "/test a1 a2 remote-review=googleplex-android", + content); + } + } + } + + @Test + public void testRecordSubmoduleLabelsWithDefaultReview() throws Exception { + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent + .append("\n") + .append("") + .append("") + .append( + "") + .append("") + .append(""); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", xmlContent.toString()); + + RepoCommand command = new RepoCommand(remoteDb); + command + .setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri) + .setRecordSubmoduleLabels(true) + .call(); + // Clone it + File directory = createTempDirectory("testBareRepo"); + try (Repository localDb = + Git.cloneRepository() + .setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()) + .call() + .getRepository(); ) { + // The .gitattributes file should exist + File gitattributes = new File(localDb.getWorkTree(), ".gitattributes"); + assertTrue("The .gitattributes file should exist", gitattributes.exists()); + try (BufferedReader reader = Files.newBufferedReader(gitattributes.toPath(), UTF_8)) { + String content = reader.readLine(); + assertEquals( + ".gitattributes content should be as expected", + "/test a1 a2 remote-review=googleplex-android", + content); + } + } + } + @Test public void testRecordShallowRecommendation() throws Exception { Repository remoteDb = createBareRepository(); 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 c5acb95bbbd..01eab37871a 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 @@ -1498,7 +1498,7 @@ private static DfsPackFile findFirstBySource(DfsPackFile[] packs, PackSource sou private DfsPackDescription midx(List coveredPacks, DfsPackDescription base) throws IOException { DfsPackDescription midx = DfsMidxWriter.writeMidx(NULL_PM, odb, - coveredPacks, base); + coveredPacks, base, null); git.tick(1); midx.setLastModified(git.getInstant().toEpochMilli()); return midx; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterBitmapsTest.java similarity index 98% rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterTest.java rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterBitmapsTest.java index ac89baaadc8..0872dd41e97 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriterBitmapsTest.java @@ -37,7 +37,7 @@ import com.googlecode.javaewah.EWAHCompressedBitmap; @RunWith(Parameterized.class) -public class DfsMidxWriterTest { +public class DfsMidxWriterBitmapsTest { @Parameterized.Parameters(name = "{0}") public static Iterable data() throws Exception { @@ -55,7 +55,7 @@ public String toString() { private TestInput ti; - public DfsMidxWriterTest(TestInput ti) { + public DfsMidxWriterBitmapsTest(TestInput ti) { this.ti = ti; } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java index 84505a8ad82..7f430412fca 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java @@ -24,12 +24,17 @@ import java.util.Optional; import java.util.zip.Deflater; +import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRng; +import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; import org.junit.Before; import org.junit.Test; @@ -164,12 +169,75 @@ public void testPrunePack() throws Exception { assertTrue(odb.has(o2)); } + @Test + public void testPrunePack_packIncludedOnlyForRefs() throws Exception { + String MAIN = "refs/heads/main"; + String DEV = "refs/heads/dev"; + ObjectId o1 = writePackWithRandomBlob(200); + writeRef(MAIN, ObjectId.zeroId(), o1); + compact(); // Creates one pack with objects and reftables + assertEquals(1, odb.listPacks().size()); + DfsPackDescription combinedPack = odb.listPacks().get(0); + + ObjectId o2 = writePackWithRandomBlob(100); + ObjectId o3 = writePackWithRandomBlob(140); + writeRef(DEV, ObjectId.zeroId(), o2); + + DfsPackCompactor compactor = new DfsPackCompactor(repo); + compactor.setReftableConfig(new ReftableConfig()); + // Add combinedPack for refs but not for data + Arrays.stream(repo.getObjectDatabase().getReftables()) + .forEach(compactor::add); + Arrays.stream(repo.getObjectDatabase().getPacks()) + .filter(p -> !p.getPackDescription().equals(combinedPack)) + .forEach(compactor::add); + compactor.compact(NullProgressMonitor.INSTANCE); + + assertTrue(odb.has(o1)); + assertTrue(odb.has(o2)); + assertTrue(odb.has(o3)); + assertEquals(o1, repo.getRefDatabase().findRef(MAIN).getObjectId()); + assertEquals(o2, repo.getRefDatabase().findRef(DEV).getObjectId()); + } + + @Test + public void testPrunePack_packIncludedOnlyForObjects() throws Exception { + String MAIN = "refs/heads/main"; + String DEV = "refs/heads/dev"; + ObjectId o1 = writePackWithRandomBlob(200); + writeRef(MAIN, ObjectId.zeroId(), o1); + compact(); // Creates one pack with objects and reftables + assertEquals(1, odb.listPacks().size()); + DfsPackDescription combinedPack = odb.listPacks().get(0); + + ObjectId o2 = writePackWithRandomBlob(100); + ObjectId o3 = writePackWithRandomBlob(140); + writeRef(DEV, ObjectId.zeroId(), o2); + + DfsPackCompactor compactor = new DfsPackCompactor(repo); + compactor.setReftableConfig(new ReftableConfig()); + // Add combinedPack for objects but not for refs + Arrays.stream(repo.getObjectDatabase().getReftables()) + .filter(p -> !p.getPackDescription().equals(combinedPack)) + .forEach(compactor::add); + Arrays.stream(repo.getObjectDatabase().getPacks()) + .forEach(compactor::add); + compactor.compact(NullProgressMonitor.INSTANCE); + + assertTrue(odb.has(o1)); + assertTrue(odb.has(o2)); + assertTrue(odb.has(o3)); + assertEquals(o1, repo.getRefDatabase().findRef(MAIN).getObjectId()); + assertEquals(o2, repo.getRefDatabase().findRef(DEV).getObjectId()); + } + private TestRepository.CommitBuilder commit() { return git.commit(); } private void compact() throws IOException { DfsPackCompactor compactor = new DfsPackCompactor(repo); + compactor.setReftableConfig(new ReftableConfig()); DfsObjDatabase objdb = repo.getObjectDatabase(); for (DfsPackFile pack : objdb.getPacks()) { DfsPackDescription d = pack.getPackDescription(); @@ -179,6 +247,9 @@ private void compact() throws IOException { compactor.exclude(pack); } } + + Arrays.stream(repo.getObjectDatabase().getReftables()) + .forEach(compactor::add); compactor.compact(null); odb.clearCache(); } @@ -202,4 +273,19 @@ private ObjectId writePackWithRandomBlob(int size) throws IOException { byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(size); return writePackWithBlob(data); } + + // RefDb does "compactDuringCommit". This only creates a new pack at the + // beginning or after compact. + private void writeRef(String name, ObjectId oldValue, ObjectId newValue) + throws IOException { + BatchRefUpdate batchRefUpdate = repo.getRefDatabase().newBatchUpdate(); + // We move the ref between blobs, it is always non fast-forward + batchRefUpdate.setAllowNonFastForwards(true); + batchRefUpdate.addCommand(new ReceiveCommand(oldValue, newValue, name)); + try (RevWalk rw = new RevWalk(repo)) { + batchRefUpdate.execute(rw, NullProgressMonitor.INSTANCE); + assertEquals(ReceiveCommand.Result.OK, + batchRefUpdate.getCommands().get(0).getResult()); + } + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java index 0f0e113b649..5e2251fc5d2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacksTest.java @@ -20,7 +20,6 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; @@ -1054,10 +1053,9 @@ public void getChecksum() throws Exception { byte[] checksum = midx.getChecksum(ctx); assertNotNull(checksum); assertEquals(20, checksum.length); - assertNotEquals('M', checksum[0]); - assertNotEquals('I', checksum[1]); - assertNotEquals('D', checksum[2]); - assertNotEquals('X', checksum[3]); + + byte[] mdixHeader = { 'M', 'I', 'D', 'X' }; + assertFalse(Arrays.equals(mdixHeader, 0, 4, checksum, 0, 4)); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java index aa2ddca2a0c..39724164cf7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingleTest.java @@ -20,7 +20,6 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; @@ -1023,10 +1022,9 @@ public void getChecksum() throws Exception { byte[] checksum = midx.getChecksum(ctx); assertNotNull(checksum); assertEquals(20, checksum.length); - assertNotEquals('M', checksum[0]); - assertNotEquals('I', checksum[1]); - assertNotEquals('D', checksum[2]); - assertNotEquals('X', checksum[3]); + + byte[] mdixHeader = { 'M', 'I', 'D', 'X' }; + assertFalse(Arrays.equals(mdixHeader, 0, 4, checksum, 0, 4)); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java index f20ca38fb9d..beaef580c23 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java @@ -9,341 +9,495 @@ */ package org.eclipse.jgit.internal.storage.dfs; -import static java.util.Arrays.asList; -import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.HashMap; import java.util.List; -import java.util.zip.Deflater; +import java.util.Map; +import java.util.Set; -import org.eclipse.jgit.junit.JGitTestUtil; -import org.eclipse.jgit.junit.TestRng; -import org.eclipse.jgit.lib.NullProgressMonitor; -import org.eclipse.jgit.lib.ObjectId; -import org.junit.Before; import org.junit.Test; public class MidxPackListTest { - InMemoryRepository db; - - @Before - public void setUp() { - db = new InMemoryRepository(new DfsRepositoryDescription("test")); - db.getObjectDatabase().setUseMultipackIndex(true); - } + PackPool packPool = new PackPool(); @Test - public void getAllPlainPacks_onlyPlain() throws IOException { - setupThreePacks(); - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - MidxPackList packList = MidxPackList.create(packs); - assertEquals(3, packList.getAllPlainPacks().size()); + public void getAllPlainPacks_onlyPlain() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + + MidxPackList packList = MidxPackList.create(a, b, c); + assertEquals(List.of(a, b, c), packList.getAllPlainPacks()); } @Test - public void getAllPlainPacks_onlyMidx() throws IOException { - setupThreePacksAndMidx(); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(1, packs.length); - MidxPackList packList = MidxPackList.create(packs); - assertEquals(3, packList.getAllPlainPacks().size()); + public void getAllPlainPacks_onlyMidx() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + + MidxPackList packList = MidxPackList.create(midx); + assertEquals(List.of(c, b, a), packList.getAllPlainPacks()); } @Test - public void getAllPlainPacks_midxPlusOne() throws IOException { - setupThreePacksAndMidx(); - writePackWithRandomBlob(60); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(2, packs.length); - MidxPackList packList = MidxPackList.create(packs); - assertEquals(4, packList.getAllPlainPacks().size()); + public void getAllPlainPacks_midxPlusOne() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + DfsPackFile d = packPool.pack("d"); + + MidxPackList packList = MidxPackList.create(d, midx); + assertEquals(List.of(d, c, b, a), packList.getAllPlainPacks()); } @Test - public void getAllPlainPacks_nestedMidx() throws IOException { - setupSixPacksThreeMidx(); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(1, packs.length); - MidxPackList packList = MidxPackList.create(packs); - assertEquals(6, packList.getAllPlainPacks().size()); + public void getAllPlainPacks_nestedMidx() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFile d = packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + DfsPackFile e = packPool.pack("e"); + DfsPackFile f = packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + MidxPackList packList = MidxPackList.create(midxTip); + assertEquals(List.of(f, e, d, c, b, a), packList.getAllPlainPacks()); } @Test - public void getAllMidxPacks_onlyPlain() throws IOException { - setupThreePacks(); + public void getAllMidxPacks_onlyPlain() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); + MidxPackList packList = MidxPackList.create(a, b, c); assertEquals(0, packList.getAllMidxPacks().size()); } @Test - public void getAllMidxPacks_onlyMidx() throws IOException { - setupThreePacksAndMidx(); - - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(1, packList.getAllMidxPacks().size()); + public void getAllMidxPacks_onlyMidx() { + packPool.pack("a"); + packPool.pack("b"); + packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + + MidxPackList packList = MidxPackList.create(midx); + assertEquals(List.of(midx), packList.getAllMidxPacks()); } @Test - public void getAllMidxPacks_midxPlusOne() throws IOException { - setupThreePacksAndMidx(); - writePackWithRandomBlob(60); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(2, packs.length); - MidxPackList packList = MidxPackList.create(packs); - assertEquals(1, packList.getAllMidxPacks().size()); + public void getAllMidxPacks_midxPlusOne() { + packPool.pack("a"); + packPool.pack("b"); + packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + DfsPackFile d = packPool.pack("d"); + + MidxPackList packList = MidxPackList.create(d, midx); + assertEquals(List.of(midx), packList.getAllMidxPacks()); } @Test - public void getAllMidxPacks_nestedMidx() throws IOException { - setupSixPacksThreeMidx(); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(1, packs.length); - MidxPackList packList = MidxPackList.create(packs); - assertEquals(3, packList.getAllMidxPacks().size()); + public void getAllMidxPacks_nestedMidx() { + packPool.pack("a"); + packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + packPool.pack("c"); + packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + packPool.pack("e"); + packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + MidxPackList packList = MidxPackList.create(midxTip); + assertEquals(List.of(midxTip, midxMiddle, midxBase), + packList.getAllMidxPacks()); } @Test - public void findAllImpactedMidx_onlyPacks() throws IOException { - setupThreePacks(); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(0, packList.findAllCoveringMidxs(asList(packs)).size()); + public void findAllImpactedMidx_onlyPacks() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + + MidxPackList packList = MidxPackList.create(a, b, c); + assertEquals(Set.of(), packList.findAllCoveringMidxs(a)); + assertEquals(Set.of(), packList.findAllCoveringMidxs(b)); + assertEquals(Set.of(), packList.findAllCoveringMidxs(c)); + assertEquals(Set.of(), packList.findAllCoveringMidxs(a, b)); } @Test - public void findAllImpactedMidx_onlyMidx() throws IOException { - setupThreePacksAndMidx(); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - MidxPackList packList = MidxPackList.create(packs); - List covered = ((DfsPackFileMidx) packs[0]) - .getAllCoveredPacks(); - assertEquals(1, packList.findAllCoveringMidxs(covered.get(0)).size()); - assertEquals(1, packList.findAllCoveringMidxs(covered.get(1)).size()); - assertEquals(1, packList.findAllCoveringMidxs(covered.get(2)).size()); - - assertEquals("multiple packs covered", 1, - packList.findAllCoveringMidxs(covered.subList(0, 2)).size()); + public void findAllImpactedMidx_onlyMidx() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + + MidxPackList packList = MidxPackList.create(midx); + assertEquals(Set.of(midx), packList.findAllCoveringMidxs(a)); + assertEquals(Set.of(midx), packList.findAllCoveringMidxs(b)); + assertEquals(Set.of(midx), packList.findAllCoveringMidxs(c)); + assertEquals(Set.of(midx), packList.findAllCoveringMidxs(a, b)); } @Test - public void findAllImpactedMidx_midxPlusOne() throws IOException { - setupThreePacksAndMidx(); - writePackWithRandomBlob(60); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(2, packs.length); - - DfsPackFile uncoveredPack = packs[0]; - List coveredPacks = ((DfsPackFileMidx) packs[1]) - .getAllCoveredPacks(); - assertEquals(3, coveredPacks.size()); - - MidxPackList packList = MidxPackList.create(packs); - assertEquals("one non covered", 0, - packList.findAllCoveringMidxs(uncoveredPack).size()); - assertEquals("one and covered", 1, - packList.findAllCoveringMidxs(coveredPacks.get(1)).size()); + public void findAllImpactedMidx_midxPlusOne() { + packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + DfsPackFile d = packPool.pack("d"); + + MidxPackList packList = MidxPackList.create(d, midx); + assertEquals("one non covered", Set.of(), + packList.findAllCoveringMidxs(d)); + assertEquals("one covered", Set.of(midx), + packList.findAllCoveringMidxs(b)); assertEquals( - "two, only one covered", 1, packList - .findAllCoveringMidxs( - List.of(uncoveredPack, coveredPacks.get(2))) - .size()); + "two, only one covered", Set.of(midx), + packList.findAllCoveringMidxs(c, d)); } @Test - public void findAllImpactedMidxs_nestedMidx() throws IOException { - setupSixPacksThreeMidx(); - - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(1, packs.length); - MidxPackList packList = MidxPackList.create(packs); - List coveredPacks = ((DfsPackFileMidx) packs[0]) - .getAllCoveredPacks(); - assertEquals(6, coveredPacks.size()); - - assertEquals("one covered tip midx", 1, - packList.findAllCoveringMidxs(coveredPacks.get(0)).size()); - assertEquals("one covered middle midx", 2, - packList.findAllCoveringMidxs(coveredPacks.get(2)).size()); - assertEquals("one covered base midx", 3, - packList.findAllCoveringMidxs(coveredPacks.get(4)).size()); - assertEquals( - "multiple covered in chain", 3, packList - .findAllCoveringMidxs(List.of(coveredPacks.get(1), - coveredPacks.get(2), coveredPacks.get(5))) - .size()); + public void findAllImpactedMidxs_nestedMidx() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFile d = packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + DfsPackFile e = packPool.pack("e"); + DfsPackFile f = packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + MidxPackList packList = MidxPackList.create(midxTip); + // Only tip + assertEquals(Set.of(midxTip), packList.findAllCoveringMidxs(e)); + assertEquals(Set.of(midxTip), packList.findAllCoveringMidxs(f)); + assertEquals(Set.of(midxTip), packList.findAllCoveringMidxs(e, f)); + + // Tip and middle + assertEquals(Set.of(midxTip, midxMiddle), + packList.findAllCoveringMidxs(c)); + assertEquals(Set.of(midxTip, midxMiddle), + packList.findAllCoveringMidxs(d)); + assertEquals(Set.of(midxTip, midxMiddle), + packList.findAllCoveringMidxs(c, d)); + assertEquals(Set.of(midxTip, midxMiddle), + packList.findAllCoveringMidxs(e, d)); + + // All three + assertEquals(Set.of(midxTip, midxMiddle, midxBase), + packList.findAllCoveringMidxs(a)); + assertEquals(Set.of(midxTip, midxMiddle, midxBase), + packList.findAllCoveringMidxs(b)); + assertEquals(Set.of(midxTip, midxMiddle, midxBase), + packList.findAllCoveringMidxs(a, b)); + assertEquals(Set.of(midxTip, midxMiddle, midxBase), + packList.findAllCoveringMidxs(c, a)); + assertEquals(Set.of(midxTip, midxMiddle, midxBase), + packList.findAllCoveringMidxs(f, c, b)); } @Test - public void getTopMidxPack_noMidx_null() throws IOException { - setupThreePacks(); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); + public void getTopMidxPack_noMidx_null() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + MidxPackList packList = MidxPackList.create(a, b, c); assertNull(packList.getTopMidxPack()); } @Test - public void getTopMidxPack_oneMidx_returned() throws IOException { - DfsPackFileMidx midx = setupThreePacksAndMidx(); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(midx.getPackDescription(), - packList.getTopMidxPack().getPackDescription()); + public void getTopMidxPack_oneMidx_returned() { + packPool.pack("a"); + packPool.pack("b"); + packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + + MidxPackList packList = MidxPackList.create(midx); + assertEquals(midx, packList.getTopMidxPack()); } @Test - public void getTopMidxPack_multipleMidx_mostRecent() throws IOException { - writePackWithRandomBlob(100); - writePackWithRandomBlob(300); - writePackWithRandomBlob(50); - writePackWithRandomBlob(400); - writePackWithRandomBlob(130); - writePackWithRandomBlob(500); - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(6, packs.length); - - // midx covers first two packs - writeMultipackIndex(Arrays.copyOfRange(packs, 4, 6), null); - - // chain of midxs covering all - DfsPackFileMidx midxBase = writeMultipackIndex( - Arrays.copyOfRange(packs, 4, 6), null); - DfsPackFileMidx midxMid = writeMultipackIndex( - Arrays.copyOfRange(packs, 2, 4), midxBase); - DfsPackFileMidx chainTwo = writeMultipackIndex( - Arrays.copyOfRange(packs, 0, 2), midxMid); - - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(chainTwo.getPackDescription(), - packList.getTopMidxPack().getPackDescription()); + public void getTopMidxPack_multipleMidx_mostRecent() { + packPool.pack("a"); + packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + packPool.pack("c"); + packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + packPool.pack("e"); + packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + MidxPackList packList = MidxPackList.create(midxTip); + assertEquals(midxTip, packList.getTopMidxPack()); } @Test - public void getPlainPacksNotCoveredBy_null_all() throws IOException { - setupThreePacks(); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(3, packList.getPlainPacksNotCoveredBy(null).size()); + public void getPlainPacksNotCoveredBy_null_all() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + MidxPackList packList = MidxPackList.create(a, b, c); + assertEquals(List.of(a, b, c), + packList.getPlainPacksNotCoveredBy(null)); } @Test public void getPlainPacksNotCoveredBy_midxCoversAll_nothing() - throws IOException { - DfsPackFileMidx midx = setupThreePacksAndMidx(); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(0, packList.getPlainPacksNotCoveredBy(midx).size()); + { + packPool.pack("a"); + packPool.pack("b"); + packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + + MidxPackList packList = MidxPackList.create(midx); + assertEquals(List.of(), packList.getPlainPacksNotCoveredBy(midx)); } @Test public void getPlainPacksNotCoveredBy_midxMissesOne_one() - throws IOException { - DfsPackFileMidx midx = setupThreePacksAndMidx(); - writePackWithBlob("getPlainPacksNotCovered_missingone" - .getBytes(StandardCharsets.UTF_8)); - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(1, packList.getPlainPacksNotCoveredBy(midx).size()); + { + packPool.pack("a"); + packPool.pack("b"); + packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + DfsPackFile d = packPool.pack("d"); + MidxPackList packList = MidxPackList.create(d, midx); + assertEquals(List.of(d), packList.getPlainPacksNotCoveredBy(midx)); } @Test - public void getPlainPacksNotCoveredBy_midxChain() throws IOException { - writePackWithRandomBlob(100); - writePackWithRandomBlob(300); - writePackWithRandomBlob(50); - writePackWithRandomBlob(400); - writePackWithRandomBlob(130); - writePackWithRandomBlob(500); - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(6, packs.length); - DfsPackFileMidx midxBase = writeMultipackIndex( - Arrays.copyOfRange(packs, 4, 6), null); - DfsPackFileMidx midxMid = writeMultipackIndex( - Arrays.copyOfRange(packs, 2, 4), midxBase); - DfsPackFileMidx midxTip = writeMultipackIndex( - Arrays.copyOfRange(packs, 0, 2), midxMid); - - MidxPackList packList = MidxPackList - .create(db.getObjectDatabase().getPacks()); - assertEquals(4, packList.getPlainPacksNotCoveredBy(midxBase).size()); - assertEquals(2, packList.getPlainPacksNotCoveredBy(midxMid).size()); - assertEquals(0, packList.getPlainPacksNotCoveredBy(midxTip).size()); + public void getPlainPacksNotCoveredBy_midxChain() { + packPool.pack("a"); + packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFile d = packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + DfsPackFile e = packPool.pack("e"); + DfsPackFile f = packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + MidxPackList packList = MidxPackList.create(midxTip); + assertEquals(List.of(f, e, d, c), + packList.getPlainPacksNotCoveredBy(midxBase)); + assertEquals(List.of(f, e), + packList.getPlainPacksNotCoveredBy(midxMiddle)); + assertEquals(List.of(), packList.getPlainPacksNotCoveredBy(midxTip)); } - private void setupThreePacks() throws IOException { - writePackWithRandomBlob(100); - writePackWithRandomBlob(300); - writePackWithRandomBlob(50); + @Test + public void builder_delete_onlyPlain() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + + MidxPackList packList = MidxPackList.create(a, b, c).edit().delete(b) + .build(); + assertEquals(List.of(a, c), packList.getAllPlainPacks()); } - private DfsPackFileMidx setupThreePacksAndMidx() throws IOException { - writePackWithRandomBlob(100); - writePackWithRandomBlob(300); - writePackWithRandomBlob(50); - return writeMultipackIndex(); + @Test + public void builder_delete_oneMidxCovering() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + + MidxPackList packList = MidxPackList.create(midx).edit().delete(b) + .build(); + assertEquals(List.of(c, a), packList.getAllPlainPacks()); + assertEquals(0, packList.getAllMidxPacks().size()); + } + + @Test + public void builder_delete_singlePackMidx() { + DfsPackFile a = packPool.pack("a"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a"); + + MidxPackList packList = MidxPackList.create(midx).edit().delete(a) + .build(); + assertEquals(List.of(), packList.getAllPlainPacks()); + assertEquals(0, packList.getAllMidxPacks().size()); } - private void setupSixPacksThreeMidx() throws IOException { - writePackWithRandomBlob(100); - writePackWithRandomBlob(300); - writePackWithRandomBlob(50); - writePackWithRandomBlob(400); - writePackWithRandomBlob(130); - writePackWithRandomBlob(500); - DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - assertEquals(6, packs.length); - DfsPackFileMidx midxBase = writeMultipackIndex( - Arrays.copyOfRange(packs, 4, 6), null); - DfsPackFileMidx midxMid = writeMultipackIndex( - Arrays.copyOfRange(packs, 2, 4), midxBase); - writeMultipackIndex(Arrays.copyOfRange(packs, 0, 2), midxMid); - assertEquals("only top midx", 1, - db.getObjectDatabase().getPacks().length); + @Test + public void builder_delete_midxPlusOne_deleteUncovered() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + DfsPackFile d = packPool.pack("d"); + + MidxPackList deleteD = MidxPackList.create(d, midx).edit().delete(d) + .build(); + assertEquals(List.of(c, b, a), deleteD.getAllPlainPacks()); + assertEquals(midx, deleteD.getTopMidxPack()); } - private DfsPackFileMidx writeMultipackIndex() throws IOException { - return writeMultipackIndex(db.getObjectDatabase().getPacks(), null); + @Test + public void builder_delete_midxPlusOne_deleteCovered() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c"); + DfsPackFile d = packPool.pack("d"); + + MidxPackList deleteB = MidxPackList.create(d, midx).edit().delete(b) + .build(); + assertEquals(List.of(d, c, a), deleteB.getAllPlainPacks()); + assertEquals(0, deleteB.getAllMidxPacks().size()); } - private DfsPackFileMidx writeMultipackIndex(DfsPackFile[] packs, - DfsPackFileMidx base) throws IOException { - List packfiles = asList(packs); - DfsPackDescription desc = DfsMidxWriter.writeMidx( - NullProgressMonitor.INSTANCE, db.getObjectDatabase(), packfiles, - base != null ? base.getPackDescription() : null); - db.getObjectDatabase().commitPack(List.of(desc), null); - return DfsPackFileMidx.create(DfsBlockCache.getInstance(), desc, - packfiles, base); + @Test + public void builder_delete_nestedMidx() { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFile d = packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + DfsPackFile e = packPool.pack("e"); + DfsPackFile f = packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + MidxPackList withoutF = MidxPackList.create(midxTip).edit().delete(f) + .build(); + assertEquals(List.of(e, d, c, b, a), withoutF.getAllPlainPacks()); + assertEquals(List.of(midxMiddle, midxBase), withoutF.getAllMidxPacks()); + assertEquals(midxMiddle, withoutF.getTopMidxPack()); + + MidxPackList withoutE = MidxPackList.create(midxTip).edit().delete(e) + .build(); + assertEquals(List.of(f, d, c, b, a), withoutE.getAllPlainPacks()); + assertEquals(List.of(midxMiddle, midxBase), withoutE.getAllMidxPacks()); + assertEquals(midxMiddle, withoutE.getTopMidxPack()); + assertEquals(Set.of(), withoutE.findAllCoveringMidxs(f)); + assertEquals(Set.of(midxMiddle, midxBase), + withoutE.findAllCoveringMidxs(a)); + + MidxPackList withoutD = MidxPackList.create(midxTip).edit().delete(d) + .build(); + assertEquals(List.of(f, e, c, b, a), withoutD.getAllPlainPacks()); + assertEquals(List.of(midxBase), withoutD.getAllMidxPacks()); + assertEquals(midxBase, withoutD.getTopMidxPack()); + + MidxPackList withoutC = MidxPackList.create(midxTip).edit().delete(c) + .build(); + assertEquals(List.of(f, e, d, b, a), withoutC.getAllPlainPacks()); + assertEquals(List.of(midxBase), withoutC.getAllMidxPacks()); + assertEquals(midxBase, withoutC.getTopMidxPack()); + assertEquals(Set.of(), withoutC.findAllCoveringMidxs(f, e, d, c)); + assertEquals(Set.of(midxBase), withoutC.findAllCoveringMidxs(a)); + + MidxPackList withoutB = MidxPackList.create(midxTip).edit().delete(b) + .build(); + assertEquals(List.of(f, e, d, c, a), withoutB.getAllPlainPacks()); + assertEquals(List.of(), withoutB.getAllMidxPacks()); + assertEquals(null, withoutB.getTopMidxPack()); + + MidxPackList withoutA = MidxPackList.create(midxTip).edit().delete(a) + .build(); + assertEquals(List.of(f, e, d, c, b), withoutA.getAllPlainPacks()); + assertEquals(List.of(), withoutA.getAllMidxPacks()); + assertEquals(null, withoutA.getTopMidxPack()); + assertEquals(Set.of(), withoutA.findAllCoveringMidxs(f, e, d, c, b)); } - private ObjectId writePackWithBlob(byte[] data) throws IOException { - DfsInserter ins = (DfsInserter) db.newObjectInserter(); - ins.setCompressionLevel(Deflater.NO_COMPRESSION); - ObjectId blobId = ins.insert(OBJ_BLOB, data); - ins.flush(); - return blobId; + @Test + public void builder_delete_nestedMidx_multipleDeletes() throws Exception { + DfsPackFile a = packPool.pack("a"); + DfsPackFile b = packPool.pack("b"); + DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b"); + DfsPackFile c = packPool.pack("c"); + DfsPackFile d = packPool.pack("d"); + DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c", + "d"); + DfsPackFile e = packPool.pack("e"); + DfsPackFile f = packPool.pack("f"); + DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e", + "f"); + + { + MidxPackList deleteFromTopAndMiddle = MidxPackList.create(midxTip) + .edit().delete(e).delete(d).build(); + assertEquals(List.of(f, c, b, a), + deleteFromTopAndMiddle.getAllPlainPacks()); + assertEquals(List.of(midxBase), + deleteFromTopAndMiddle.getAllMidxPacks()); + assertEquals(midxBase, deleteFromTopAndMiddle.getTopMidxPack()); + } + { + MidxPackList deleteFromMiddleAndTop = MidxPackList.create(midxTip) + .edit().delete(d).delete(e).build(); + assertEquals(List.of(f, c, b, a), + deleteFromMiddleAndTop.getAllPlainPacks()); + assertEquals(List.of(midxBase), + deleteFromMiddleAndTop.getAllMidxPacks()); + assertEquals(midxBase, deleteFromMiddleAndTop.getTopMidxPack()); + } + { + MidxPackList deleteAllFromMidx = MidxPackList.create(midxTip).edit() + .delete(d).delete(c).build(); + assertEquals(List.of(f, e, b, a), + deleteAllFromMidx.getAllPlainPacks()); + assertEquals(List.of(midxBase), + deleteAllFromMidx.getAllMidxPacks()); + assertEquals(midxBase, deleteAllFromMidx.getTopMidxPack()); + } } - // Do not use the size twice into the same test (it gives the same blob!) - private ObjectId writePackWithRandomBlob(int size) throws IOException { - byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(size); - return writePackWithBlob(data); + private static final class PackPool { + private static final DfsRepositoryDescription repoDesc = new DfsRepositoryDescription( + "midxpacklisttest"); + + private final Map knownPacks = new HashMap<>(); + + DfsPackFile pack(String name) { + DfsPackDescription dsc = new DfsPackDescription(repoDesc, name, GC); + DfsPackFile p = new DfsPackFile(DfsBlockCache.getInstance(), dsc); + knownPacks.put(name, p); + return p; + } + + DfsPackFileMidx midx(String name, DfsPackFileMidx base, + String... coveredPacks) { + DfsPackDescription dsc = new DfsPackDescription(repoDesc, name, GC); + dsc.addFileExt(MULTI_PACK_INDEX); + dsc.setCoveredPacks(Arrays.stream(coveredPacks).map(knownPacks::get) + .map(DfsPackFile::getPackDescription).toList()); + if (base != null) { + dsc.setMultiPackIndexBase(base.getPackDescription()); + } + return DfsPackFileMidx.create(DfsBlockCache.getInstance(), dsc, + knownPacks.values().stream().toList(), base); + } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java index 321ea01447f..728feeae982 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalkTest.java @@ -19,6 +19,7 @@ import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.jgit.internal.revwalk.RefAdvancerWalk; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.RevCommit; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/MidxWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/MidxWriterTest.java new file mode 100644 index 00000000000..bb45d0a3633 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/MidxWriterTest.java @@ -0,0 +1,91 @@ +package org.eclipse.jgit.internal.storage.file; + +import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; +import static org.eclipse.jgit.lib.Constants.MIDX_FILE; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; + +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader; +import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.WindowCacheConfig; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.junit.Before; +import org.junit.Test; + +public class MidxWriterTest extends LocalDiskRepositoryTestCase { + private int streamThreshold = 16 * 1024; + + private final static ObjectId UNKNOWN_OBJ = ObjectId + .fromString("678668bdd3a609c6e1d7fea516e9fc1ed4f50ad2"); + + private FileRepository repo; + + private TestRepository tr; + +// private WindowCursor wc; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + + WindowCacheConfig cfg = new WindowCacheConfig(); + cfg.setStreamFileThreshold(streamThreshold); + cfg.install(); + + repo = createBareRepository(); + tr = new TestRepository<>(repo); +// wc = (WindowCursor) repo.newObjectReader(); + } + + @Test + public void midx_write() throws Exception { + TestRepository.BranchBuilder branch = tr + .branch("refs/heads/main"); + RevBlob contentsOfA = tr.blob("contents of a"); + RevCommit commitA = branch.commit().add("a.txt", contentsOfA).create(); + tr.packAndPrune(); + + RevBlob contentsOfB = tr.blob("contents of b"); + RevCommit commitB = branch.commit().add("b.txt", contentsOfB).create(); + tr.packAndPrune(); + + RevCommit commitC = branch.commit().add("c.txt", "contents of c commit") + .create(); + tr.packAndPrune(); + + File midxFile = new File(repo.getObjectDatabase().getPackDirectory(), + MIDX_FILE); + assertFalse(midxFile.exists()); + MidxWriter.writeMidx( + new TextProgressMonitor(new OutputStreamWriter(System.out, + StandardCharsets.UTF_8)), + repo, repo.getObjectDatabase().getPacks(), midxFile, + new PackConfig()); + assertTrue(midxFile.exists()); + + MultiPackIndex midx = MultiPackIndexLoader.open(midxFile); + assertTrue(midx.hasObject(commitA)); + assertTrue(midx.hasObject(commitB)); + assertTrue(midx.hasObject(commitC)); + assertFalse(midx.hasObject(UNKNOWN_OBJ)); + + File midxBitmaps = new File(repo.getObjectDatabase().getPackDirectory(), + String.format("%s-%s.%s", MIDX_FILE, + ObjectId.fromRaw(midx.getChecksum()).name(), + BITMAP_INDEX.getExtension())); + assertTrue(midxBitmaps.exists()); + + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackDirectoryTest.java new file mode 100644 index 00000000000..b04d31a2d7a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackDirectoryTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2026, 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.internal.storage.file; + +import static org.eclipse.jgit.lib.Constants.MIDX_FILE; +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.storage.file.WindowCacheConfig; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.junit.Before; +import org.junit.Test; + +public class PackDirectoryTest extends LocalDiskRepositoryTestCase { + private int streamThreshold = 16 * 1024; + + private FileRepository repo; + + private TestRepository tr; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + + WindowCacheConfig cfg = new WindowCacheConfig(); + cfg.setStreamFileThreshold(streamThreshold); + cfg.install(); + + mockSystemReader.getSystemConfig().setBoolean( + ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_MULTIPACKINDEX, true); + + repo = createBareRepository(); + tr = new TestRepository<>(repo); + } + + @Test + public void getPacks_midxReplacesCoveredPacks() throws Exception { + createThreePacks(); + Collection packs = repo.getObjectDatabase().getPacks(); + assertEquals(3, packs.size()); + writeMidxOverAllPacks(); + + // Reading now should return the midx + packs = repo.getObjectDatabase().getPacks(); + assertEquals(1, packs.size()); + + tr.branch("refs/heads/main").commit().add("more.txt", "booooo") + .create(); + tr.packAndPrune(); + + packs = repo.getObjectDatabase().getPacks(); + assertEquals(2, packs.size()); + } + + private TestRepoObjects createThreePacks() throws Exception { + TestRepository.BranchBuilder branch = tr + .branch("refs/heads/main"); + RevBlob contentsOfA = tr.blob("contents of a"); + RevCommit commitA = branch.commit().add("a.txt", contentsOfA).create(); + tr.packAndPrune(); + + RevBlob contentsOfB = tr.blob("contents of b"); + RevCommit commitB = branch.commit().add("b.txt", contentsOfB).create(); + tr.packAndPrune(); + + RevCommit commitC = branch.commit().add("c.txt", "contents of c commit") + .create(); + tr.packAndPrune(); + + Map midxOffsets = Map.of(commitA, 163, commitB, 12, + commitC, 694, contentsOfA, 399, contentsOfB, 421); + + return new TestRepoObjects(commitA, commitB, commitC, contentsOfA, + contentsOfB, midxOffsets); + } + + private record TestRepoObjects(RevCommit commitA, RevCommit commitB, + RevCommit commitC, RevBlob contentsOfA, RevBlob contentsOfB, + Map midxOffsets) { + } + + private void writeMidxOverAllPacks() throws IOException { + Collection packs = tr.getRepository().getObjectDatabase() + .getPacks(); + assertEquals(3, packs.size()); + + File midxDest = new File(repo.getObjectDatabase().getPackDirectory(), + MIDX_FILE); + MidxWriter.writeMidx(new TextProgressMonitor(), repo, packs, midxDest, + new PackConfig(repo)); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackMidxTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackMidxTest.java new file mode 100644 index 00000000000..7a497d6457b --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackMidxTest.java @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2026, 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.file; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.storage.file.WindowCacheConfig; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.junit.Before; +import org.junit.Test; + +public class PackMidxTest extends LocalDiskRepositoryTestCase { + private int streamThreshold = 16 * 1024; + + private final static ObjectId UNKNOWN_OBJ = ObjectId + .fromString("678668bdd3a609c6e1d7fea516e9fc1ed4f50ad2"); + + private FileRepository repo; + + private TestRepository tr; + + private WindowCursor wc; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + + WindowCacheConfig cfg = new WindowCacheConfig(); + cfg.setStreamFileThreshold(streamThreshold); + cfg.install(); + + repo = createBareRepository(); + tr = new TestRepository<>(repo); + wc = (WindowCursor) repo.newObjectReader(); + } + + @Test + public void midx_hasObject() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + assertTrue(midx.hasObject(objs.commitA)); + assertTrue(midx.hasObject(objs.commitB)); + assertTrue(midx.hasObject(objs.commitC)); + assertTrue(midx.hasObject(objs.contentsOfB)); + assertTrue(midx.hasObject(objs.contentsOfA)); + assertFalse(midx.hasObject(UNKNOWN_OBJ)); + } + + @Test + public void midx_getObjectCount() throws Exception { + createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + assertEquals(9, midx.getObjectCount()); + } + + @Test + public void midx_getObjectSize_byId() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + assertEquals(getObjectSizeFromObjectDb(objs.commitA), + midx.getObjectSize(wc, objs.commitA)); + assertEquals(getObjectSizeFromObjectDb(objs.commitB), + midx.getObjectSize(wc, objs.commitB)); + assertEquals(getObjectSizeFromObjectDb(objs.commitC), + midx.getObjectSize(wc, objs.commitC)); + assertEquals(getObjectSizeFromObjectDb(objs.contentsOfA), + midx.getObjectSize(wc, objs.contentsOfA)); + assertEquals(getObjectSizeFromObjectDb(objs.contentsOfB), + midx.getObjectSize(wc, objs.contentsOfB)); + assertEquals(-1, midx.getObjectSize(wc, UNKNOWN_OBJ)); + } + + @Test + public void midx_getObjectSize_byOffset() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + Map midxOffsets = objs.midxOffsets; + Integer offsetCommitA = midxOffsets.get(objs.commitA); + assertEquals(getObjectSizeFromObjectDb(objs.commitA), + midx.getObjectSize(wc, offsetCommitA)); + + Integer offsetCommitB = midxOffsets.get(objs.commitB); + assertEquals(getObjectSizeFromObjectDb(objs.commitB), + midx.getObjectSize(wc, offsetCommitB)); + + Integer offsetCommitC = midxOffsets.get(objs.commitC); + assertEquals(getObjectSizeFromObjectDb(objs.commitC), + midx.getObjectSize(wc, offsetCommitC)); + + Integer offsetContentsOfA = midxOffsets.get(objs.contentsOfA); + assertEquals(getObjectSizeFromObjectDb(objs.contentsOfA), + midx.getObjectSize(wc, offsetContentsOfA)); + + Integer offsetContentsOfB = midxOffsets.get(objs.contentsOfB); + assertEquals(midx.getObjectSize(wc, objs.contentsOfB), + midx.getObjectSize(wc, offsetContentsOfB)); + } + + private long getObjectSizeFromObjectDb(AnyObjectId oid) throws IOException { + return repo.getObjectDatabase().getObjectSize(wc, oid); + } + + @Test + public void midx_get_byOid() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + assertEquals("contents of a", midxGet(midx, objs.contentsOfA)); + assertEquals("contents of b", midxGet(midx, objs.contentsOfB)); + String commitContent = midxGet(midx, objs.commitB); + assertTrue(commitContent + .startsWith("tree 4ad3577dd1af1fe281a6e55d48cee2d397d570d5")); + assertTrue(commitContent + .contains("author J. Author ")); + + assertNull(midx.get(wc, UNKNOWN_OBJ)); + } + + private String midxGet(PackMidx midx, AnyObjectId oid) throws IOException { + ObjectLoader ol = midx.get(wc, oid); + return new String(ol.getCachedBytes(), UTF_8); + } + + @Test + public void midx_load_byOffset() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + Map midxOffsets = objs.midxOffsets; + assertEquals("contents of a", + midxLoad(midx, midxOffsets.get(objs.contentsOfA))); + assertEquals("contents of b", + midxLoad(midx, midxOffsets.get(objs.contentsOfB))); + String commitContent = midxLoad(midx, midxOffsets.get(objs.commitB)); + assertTrue(commitContent + .startsWith("tree 4ad3577dd1af1fe281a6e55d48cee2d397d570d5")); + assertTrue(commitContent + .contains("author J. Author ")); + } + + private String midxLoad(PackMidx midx, int pos) throws IOException { + ObjectLoader ol = midx.load(wc, pos); + return new String(ol.getCachedBytes(), UTF_8); + } + + @Test + public void midx_findObject_byOffset() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + Map midxOffsets = objs.midxOffsets; + assertEquals(objs.commitA, + midx.findObjectForOffset(midxOffsets.get(objs.commitA))); + assertEquals(objs.commitB, + midx.findObjectForOffset(midxOffsets.get(objs.commitB))); + assertEquals(objs.commitC, + midx.findObjectForOffset(midxOffsets.get(objs.commitC))); + assertEquals(objs.contentsOfA, + midx.findObjectForOffset(midxOffsets.get(objs.contentsOfA))); + assertEquals(objs.contentsOfB, + midx.findObjectForOffset(midxOffsets.get(objs.contentsOfB))); + } + + @Test + public void midx_getObjectType() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + Map midxOffsets = objs.midxOffsets; + assertEquals(Constants.OBJ_COMMIT, + midx.getObjectType(wc, midxOffsets.get(objs.commitA))); + assertEquals(Constants.OBJ_COMMIT, + midx.getObjectType(wc, midxOffsets.get(objs.commitB))); + assertEquals(Constants.OBJ_COMMIT, + midx.getObjectType(wc, midxOffsets.get(objs.commitC))); + assertEquals(Constants.OBJ_BLOB, + midx.getObjectType(wc, midxOffsets.get(objs.contentsOfA))); + assertEquals(Constants.OBJ_BLOB, + midx.getObjectType(wc, midxOffsets.get(objs.contentsOfB))); + } + + @Test + public void midx_iterator() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + Map midxOffsets = objs.midxOffsets; + Iterator it = midx.iterator(); + assertIteratorEntry(it, objs.contentsOfB, + midxOffsets.get(objs.contentsOfB)); + it.next(); + it.next(); + assertIteratorEntry(it, objs.commitB, midxOffsets.get(objs.commitB)); + assertIteratorEntry(it, objs.commitA, midxOffsets.get(objs.commitA)); + it.next(); + it.next(); + assertIteratorEntry(it, objs.contentsOfA, + midxOffsets.get(objs.contentsOfA)); + assertIteratorEntry(it, objs.commitC, midxOffsets.get(objs.commitC)); + assertFalse(it.hasNext()); + } + + private void assertIteratorEntry(Iterator it, + ObjectId oid, int offset) { + assertTrue(it.hasNext()); + PackIndex.MutableEntry next = it.next(); + assertEquals(oid, next.toObjectId()); + assertEquals(offset, next.getOffset()); + } + + @Test + public void midx_packIndex_hasObject() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + PackIndex index = midx.getIndex(); + assertTrue(index.hasObject(objs.commitA)); + assertTrue(index.hasObject(objs.commitB)); + assertTrue(index.hasObject(objs.commitC)); + assertTrue(index.hasObject(objs.contentsOfA)); + assertTrue(index.hasObject(objs.contentsOfB)); + assertFalse(index.hasObject(UNKNOWN_OBJ)); + } + + @Test + public void midx_packIndex_findPosition_getByPosition() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + PackIndex index = midx.getIndex(); + assertEquals(objs.commitA, + index.getObjectId(index.findPosition(objs.commitA))); + assertEquals(objs.commitB, + index.getObjectId(index.findPosition(objs.commitB))); + assertEquals(objs.commitC, + index.getObjectId(index.findPosition(objs.commitC))); + assertEquals(objs.contentsOfA, + index.getObjectId(index.findPosition(objs.contentsOfA))); + assertEquals(objs.contentsOfB, + index.getObjectId(index.findPosition(objs.contentsOfB))); + assertEquals(-1, index.findPosition(UNKNOWN_OBJ)); + } + + @Test + public void midx_packIndex_findOffset() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + Map offsets = objs.midxOffsets; + PackIndex index = midx.getIndex(); + assertEquals((long) offsets.get(objs.commitA), + index.findOffset(objs.commitA)); + assertEquals((long) offsets.get(objs.commitB), + index.findOffset(objs.commitB)); + assertEquals((long) offsets.get(objs.commitC), + index.findOffset(objs.commitC)); + assertEquals((long) offsets.get(objs.contentsOfA), + index.findOffset(objs.contentsOfA)); + assertEquals((long) offsets.get(objs.contentsOfB), + index.findOffset(objs.contentsOfB)); + assertEquals(-1, index.findOffset(UNKNOWN_OBJ)); + } + + @Test + public void midx_reversePackIndex_findObject() throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + List offsetOrdered = inRidxOrder(objs.midxOffsets); + PackReverseIndex ridx = midx.getReverseIdx(); + + assertFalse(offsetOrdered.isEmpty()); + for (int i = 0; i < offsetOrdered.size(); i++) { + ObjectOffset entry = offsetOrdered.get(i); + assertEquals(entry.obj().getId(), ridx.findObject(entry.offset())); + } + } + + @Test + public void midx_reversePackIndex_findPosition_findObjectByPosition() + throws Exception { + TestRepoObjects objs = createThreePacks(); + PackMidx midx = writeAndOpenMidxAllPacks(); + + List offsetOrdered = inRidxOrder(objs.midxOffsets); + PackReverseIndex ridx = midx.getReverseIdx(); + + assertFalse(offsetOrdered.isEmpty()); + for (int i = 0; i < offsetOrdered.size(); i++) { + ObjectOffset entry = offsetOrdered.get(i); + assertEquals(entry.obj(), ridx + .findObjectByPosition(ridx.findPosition(entry.offset()))); + } + } + + private PackMidx writeAndOpenMidxAllPacks() throws IOException { + Collection packs = ((ObjectDirectory) tr.getRepository() + .getObjectDatabase()).getPacks(); + assertEquals(3, packs.size()); + + File midxDest = new File(repo.getObjectDatabase().getPackDirectory(), + Constants.MIDX_FILE); + MidxWriter.writeMidx(new TextProgressMonitor(), repo, packs, midxDest, + new PackConfig(repo)); + + return new PackMidx(new Config(), midxDest, packs.stream().toList()); + + } + + private TestRepoObjects createThreePacks() throws Exception { + TestRepository.BranchBuilder branch = tr + .branch("refs/heads/main"); + RevBlob contentsOfA = tr.blob("contents of a"); + RevCommit commitA = branch.commit().add("a.txt", contentsOfA).create(); + tr.packAndPrune(); + + RevBlob contentsOfB = tr.blob("contents of b"); + RevCommit commitB = branch.commit().add("b.txt", contentsOfB).create(); + tr.packAndPrune(); + + RevCommit commitC = branch.commit().add("c.txt", "contents of c commit") + .create(); + tr.packAndPrune(); + + Map midxOffsets = Map.of(commitA, 163, commitB, 12, + commitC, 694, contentsOfA, 399, contentsOfB, 421); + + return new TestRepoObjects(commitA, commitB, commitC, contentsOfA, + contentsOfB, midxOffsets); + } + + private record TestRepoObjects(RevCommit commitA, RevCommit commitB, + RevCommit commitC, RevBlob contentsOfA, RevBlob contentsOfB, + Map midxOffsets) { + } + + private List inRidxOrder(Map objs) { + return objs.entrySet().stream() + .map(e -> new ObjectOffset(e.getKey(), e.getValue())) + .sorted(Comparator.comparing(ObjectOffset::offset)).toList(); + } + + private record ObjectOffset(RevObject obj, Integer offset) { + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java index 6552bac8af6..4dc40df52ca 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java @@ -46,6 +46,7 @@ import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.PackedRefsTrait; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref.Storage; import org.eclipse.jgit.lib.RefDatabase; @@ -71,6 +72,8 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase { private RevTag v1_0; + private RevTag v2_0; + @Override @Before public void setUp() throws Exception { @@ -85,7 +88,8 @@ public void refDirectorySetup() throws Exception { repo = new TestRepository<>(diskRepo); A = repo.commit().create(); B = repo.commit(repo.getRevWalk().parseCommit(A)); - v1_0 = repo.tag("v1_0", B); + v1_0 = repo.tag("v1_0", A); + v2_0 = repo.tag("v2_0", B); repo.getRevWalk().parseBody(v1_0); } @@ -997,16 +1001,16 @@ public void testGetRefs_PackedWithPeeled() throws IOException { final Ref tag = all.get("refs/tags/v1.0"); assertEquals(A, master.getObjectId()); - assertTrue(master.isPeeled()); + assertFalse(master.isPeeled()); assertNull(master.getPeeledObjectId()); assertEquals(B, other.getObjectId()); - assertTrue(other.isPeeled()); + assertFalse(other.isPeeled()); assertNull(other.getPeeledObjectId()); assertSame(master, head.getTarget()); assertEquals(A, head.getObjectId()); - assertTrue(head.isPeeled()); + assertFalse(head.isPeeled()); assertNull(head.getPeeledObjectId()); assertEquals(v1_0, tag.getObjectId()); @@ -1063,6 +1067,76 @@ public void test_repack() throws Exception { assertEquals(v0_1.getId(), all.get("refs/tags/v0.1").getObjectId()); } + @Test + public void testNewPackFileHasAllTraits()throws Exception { + writeLooseRef("refs/heads/master", B); + + PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo); + packRefsCommand.setAll(true); + packRefsCommand.call(); + + File packedRefsFile = new File(diskRepo.getCommonDirectory(), Constants.PACKED_REFS); + + String content = read(packedRefsFile); + String firstLine = content.split("\n")[0]; + assertTrue("packed-refs should have header with sorted", + firstLine.contains(" sorted")); + assertTrue("packed-refs should have header with peeled", + firstLine.contains(" peeled")); + assertTrue("packed-refs should have header with fully-peeled", + firstLine.contains(" fully-peeled")); + } + + @Test + public void autoPeelAnyUnpeeledTags() throws Exception { + writePackedRefs("# pack-refs with: sorted \n" + + v1_0.name() + " refs/tags/peeled\n" + + "^" + v1_0.getObject().name() + "\n" + + v2_0.name() + " refs/tags/unpeeled" + ); + + writeLooseRef("refs/tags/other", B); + + PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo); + packRefsCommand.setAll(true); + packRefsCommand.call(); + + File packedRefsFile = new File(diskRepo.getCommonDirectory(), Constants.PACKED_REFS); + String content = read(packedRefsFile); + String firstLine = content.split("\n")[0]; + assertTrue("packed-refs should have peeled trait", firstLine.contains(" peeled")); + assertTrue("packed-refs should have fully-peeled trait", + firstLine.contains(" fully-peeled")); + + assertTrue(refdir.getPackedRefs().traits().contains(PackedRefsTrait.PEELED)); + assertTrue(refdir.getPackedRefs().get("refs/tags/peeled").isPeeled()); + assertTrue(refdir.getPackedRefs().get("refs/tags/unpeeled").isPeeled()); + } + + @Test + public void preservePeeledTraitIfPreviouslyPeeled() throws Exception { + writePackedRefs("# pack-refs with: sorted peeled\n" + + v1_0.name() + " refs/tags/peeled\n" + + "^" + v1_0.getObject().name() + "\n" + ); + + writeLooseRef("refs/tags/unpeeled-loose", v2_0); + + PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo); + packRefsCommand.setAll(true); + packRefsCommand.call(); + + File packedRefsFile = new File(diskRepo.getCommonDirectory(), Constants.PACKED_REFS); + String content = read(packedRefsFile); + String firstLine = content.split("\n")[0]; + assertTrue("packed-refs should have peeled trait", firstLine.contains(" peeled")); + + assertTrue(refdir.getPackedRefs().traits().contains(PackedRefsTrait.PEELED)); + assertTrue(refdir.getPackedRefs().get("refs/tags/peeled").isPeeled()); + // new loose ref/tags/.. ares peeled + assertTrue(refdir.getPackedRefs().get("refs/tags/unpeeled-loose").isPeeled()); + } + @Test public void testPackedRefsHeaderWithSorted() throws Exception { writeLooseRef("refs/heads/master", A); @@ -1117,6 +1191,46 @@ public void testPackedRefsUnsortedGetsSorted() throws Exception { ); } + @Test + public void preserveFullyPeeledTraitIfPreviouslyFullyPeeled() throws Exception { + writePackedRefs("# pack-refs with: sorted fully-peeled\n" + + v1_0.name() + " refs/other/peeled\n" + + "^" + v1_0.getObject().name() + "\n" + ); + + writeLooseRef("refs/other/unpeeled-loose", v2_0); + + PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo); + packRefsCommand.setAll(true); + packRefsCommand.call(); + + File packedRefsFile = new File(diskRepo.getCommonDirectory(), Constants.PACKED_REFS); + String content = read(packedRefsFile); + String firstLine = content.split("\n")[0]; + assertTrue("packed-refs should have fully-peeled trait", + firstLine.contains(" fully-peeled")); + + assertTrue(refdir.getPackedRefs().traits().contains(PackedRefsTrait.PEELED)); + assertTrue(refdir.getPackedRefs().get("refs/other/peeled").isPeeled()); + // new loose refs ares peeled + assertTrue(refdir.getPackedRefs().get("refs/other/unpeeled-loose").isPeeled()); + } + + @Test + public void testPackRefsPeelsTagOutsideTagsNamespace() throws Exception { + writeLooseRef("refs/other/tag-v1.0", v1_0); + + PackRefsCommand packRefsCommand = new PackRefsCommand(diskRepo); + packRefsCommand.setAll(true); + packRefsCommand.call(); + + Ref tag = refdir.getPackedRefs().get("refs/other/tag-v1.0"); + + assertNotNull("tag ref should be packed", tag); + assertTrue("tag should be peeled", tag.isPeeled()); + assertEquals(v1_0.getObject(), tag.getPeeledObjectId()); + } + @Test public void testFindRef_EmptyDatabase() throws IOException { Ref r; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxIteratorsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxIteratorsTest.java index 19a2cdeb98c..310542345cb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxIteratorsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxIteratorsTest.java @@ -31,8 +31,7 @@ public void fromPackIndexIterator_basicIteration() { PackIndex index1 = indexOf(object("000001", 500), object("000003", 3000), object("000005", 1500)); - MidxIterator it = MidxIterators.fromPackIndexIterator("index1", - index1.iterator()); + MidxIterator it = MidxIterators.fromPackIndexIterator("index1", index1); assertNextEntry(it, "000001", 0, 500); assertNextEntry(it, "000003", 0, 3000); assertNextEntry(it, "000005", 0, 1500); @@ -44,8 +43,7 @@ public void fromPackIndexIterator_peek() { PackIndex index1 = indexOf(object("000001", 500), object("000003", 3000), object("000005", 1500)); - MidxIterator it = MidxIterators.fromPackIndexIterator("index1", - index1.iterator()); + MidxIterator it = MidxIterators.fromPackIndexIterator("index1", index1); assertPeekEntry(it, "000001", 0, 500); assertPeekEntry(it, "000001", 0, 500); assertNextEntry(it, "000001", 0, 500); @@ -60,20 +58,35 @@ public void fromPackIndexIterator_peek() { assertFalse(it.hasNext()); } + @Test + public void fromPackIndexIterator_reset() { + PackIndex index1 = indexOf(object("000001", 500), + object("000003", 3000), object("000005", 1500)); + + MidxIterator it = MidxIterators.fromPackIndexIterator("index1", index1); + while (it.hasNext()) { + it.next(); + } + it.reset(); + assertNextEntry(it, "000001", 0, 500); + assertNextEntry(it, "000003", 0, 3000); + + it.reset(); + assertPeekEntry(it, "000001", 0, 500); + } + @Test public void fromPackIndexIterator_getPackNames() { PackIndex index1 = indexOf(object("000001", 500), object("000003", 1500), object("000005", 3000)); - MidxIterator it = MidxIterators.fromPackIndexIterator("index1", - index1.iterator()); + MidxIterator it = MidxIterators.fromPackIndexIterator("index1", index1); assertEquals(List.of("index1"), it.getPackNames()); } @Test public void fromPackIndexIterator_empty() { - PackIndex index1 = indexOf(); MidxIterator it = MidxIterators.fromPackIndexIterator("index1", - index1.iterator()); + indexOf()); assertFalse(it.hasNext()); } @@ -104,10 +117,8 @@ public void join_basicIteration_packIndexIterators() { object("000003", 1500), object("000004", 3000)); List packIts = List.of( - MidxIterators.fromPackIndexIterator("index1", - idxOne.iterator()), - MidxIterators.fromPackIndexIterator("index2", - idxTwo.iterator())); + MidxIterators.fromPackIndexIterator("index1", idxOne), + MidxIterators.fromPackIndexIterator("index2", idxTwo)); MidxIterator it = MidxIterators.join(packIts); assertNextEntry(it, "000001", 0, 500); assertNextEntry(it, "000002", 1, 500); @@ -136,6 +147,24 @@ public void join_duplicates_inPackIdOrder() { assertFalse(it.hasNext()); } + @Test + public void join_duplicates_inPackIdOrder_shift() { + FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 5, + List.of(new IndexEntry("000001", 4, 501), + new IndexEntry("000003", 2, 1501))); + + FakeMidxIterator itTwo = FakeMidxIterator.from("itTwo", 2, + List.of(new IndexEntry("000001", 0, 500), + new IndexEntry("000003", 1, 1500))); + + MidxIterator it = MidxIterators.join(List.of(itOne, itTwo)); + assertNextEntry(it, "000001", 4, 501); + assertNextEntry(it, "000001", 5, 500); + assertNextEntry(it, "000003", 2, 1501); + assertNextEntry(it, "000003", 6, 1500); + assertFalse(it.hasNext()); + } + @Test public void join_peek() { FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 2, @@ -165,6 +194,29 @@ public void join_peek() { assertFalse(it.hasNext()); } + @Test + public void join_reset() { + FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 2, + List.of(new IndexEntry("000001", 0, 500), + new IndexEntry("000003", 1, 1500))); + + FakeMidxIterator itTwo = FakeMidxIterator.from("itTwo", 2, + List.of(new IndexEntry("000002", 0, 500), + new IndexEntry("000004", 1, 1500))); + + MidxIterator it = MidxIterators.join(List.of(itOne, itTwo)); + while (it.hasNext()) { + it.next(); + } + + it.reset(); + assertNextEntry(it, "000001", 0, 500); + assertNextEntry(it, "000002", 2, 500); + + it.reset(); + assertPeekEntry(it, "000001", 0, 500); + } + @Test public void join_getPackNames() { FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 2, @@ -236,6 +288,49 @@ public void dedup_peek() { assertFalse(it.hasNext()); } + @Test + public void dedup_reset() { + FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 2, + List.of(new IndexEntry("000001", 0, 500), + new IndexEntry("000001", 1, 600), + new IndexEntry("000003", 0, 1500), + new IndexEntry("000003", 1, 1501), + new IndexEntry("000005", 0, 200), + new IndexEntry("000005", 1, 201))); + + MidxIterator it = MidxIterators.dedup(itOne); + while (it.hasNext()) { + it.next(); + } + it.reset(); + assertNextEntry(it, "000001", 0, 500); + assertNextEntry(it, "000003", 0, 1500); + + it.reset(); + assertPeekEntry(it, "000001", 0, 500); + } + + @Test + public void dedup_reset_sameElement() { + FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 2, + List.of(new IndexEntry("000001", 0, 500), + new IndexEntry("000001", 1, 600), + new IndexEntry("000001", 2, 1500), + new IndexEntry("000001", 3, 1501), + new IndexEntry("000001", 4, 200), + new IndexEntry("000001", 5, 201))); + + MidxIterator it = MidxIterators.dedup(itOne); + while (it.hasNext()) { + it.next(); + } + it.reset(); + assertNextEntry(it, "000001", 0, 500); + + it.reset(); + assertPeekEntry(it, "000001", 0, 500); + } + @Test public void dedup_getPackNames() { FakeMidxIterator itOne = FakeMidxIterator.from("itOne", 4, @@ -322,6 +417,10 @@ public MultiPackIndex.MutableEntry next() { return entries.get(position++).asMutableEntry(); } + @Override + public void reset() { + position = 0; + } } record IndexEntry(String shortOid, int packId, int offset) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxMetadataReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxMetadataReaderTest.java new file mode 100644 index 00000000000..b41d6c3295f --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxMetadataReaderTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2026, 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.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.eclipse.jgit.junit.JGitTestUtil; +import org.junit.Test; + +public class MidxMetadataReaderTest { + @Test + public void load_validFile_basic_upstream() throws Exception { + MidxMetadataReader.MidxMetadata meta = MidxMetadataReader + .read(JGitTestUtil.getTestResourceFile("multi-pack-index.v1")); + assertEquals(26, meta.packNames().size()); + + byte[] expected = new byte[] { 15, -10, -96, 97, 76, 13, -72, 95, 106, + 15, -55, -12, 18, -13, 50, 33, 120, -113, 71, -119 }; + assertArrayEquals(expected, meta.checksum()); + } +} 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 index 3c7e27d6670..a59e8749172 100644 --- 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 @@ -17,7 +17,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.LinkedHashMap; import java.util.List; import org.eclipse.jgit.internal.storage.file.PackIndex; @@ -64,13 +63,11 @@ public void load_validFile_basic_jgit() throws Exception { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - LinkedHashMap packs = new LinkedHashMap<>(3); - packs.put("p1", idxOne); - packs.put("p2", idxTwo); - packs.put("p3", idxThree); + PackIndexMerger data = PackIndexMerger.builder().addPack("p1", idxOne) + .addPack("p2", idxTwo).addPack("p3", idxThree).build(); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); 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 index a2c86f3dce0..75a5a956cdf 100644 --- 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 @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Set; @@ -114,7 +113,7 @@ public void jgit_largeOffsetChunk() throws IOException { "0000000000000000000000000000000000000002", (1L << 35)), new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000003", 13))); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger packs = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -145,7 +144,7 @@ public void jgit_largeOffset_noChunk() throws IOException { "0000000000000000000000000000000000000002", 501), new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000003", 13))); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger packs = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -182,7 +181,7 @@ public void jgit_resolve() throws IOException { // Match "32fe829a1c000000000000000000000000000010"); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger packs = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -226,7 +225,7 @@ public void jgit_resolve_matchLimit() throws IOException { // Match "32fe829a1c000000000000000000000000000010"); - LinkedHashMap packs = orderedMapOf("r1", idxOne, + PackIndexMerger packs = midxDataFor("r1", idxOne, "r2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -261,7 +260,7 @@ public void jgit_resolve_noMatches() throws IOException { "bbbbbb0000000000000000000000000000000003", "32fe829a1c000000000000000000000000000010"); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger packs = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -292,7 +291,7 @@ public void jgit_resolve_noMatches_last() throws IOException { "bbbbbb0000000000000000000000000000000003", "32fe829a1c000000000000000000000000000010"); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger packs = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -314,11 +313,11 @@ public void jgit_resolve_empty() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -377,11 +376,11 @@ private static MultiPackIndex createMultiPackIndex() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo, "p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); return MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -398,11 +397,11 @@ public void jgit_getObjectCount_emtpy() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -433,11 +432,11 @@ public void jgit_findBitmapPosition() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo, "p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -495,11 +494,11 @@ public void jgit_getObjectAtBitmapPosition() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo, "p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -563,11 +562,11 @@ public void jgit_iterator_emtpy() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -591,11 +590,11 @@ public void jgit_iterator_peek() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000015", 1501))); - LinkedHashMap packs = orderedMapOf("p1", idxOne, + PackIndexMerger data = midxDataFor("p1", idxOne, "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, packs); + writer.write(NullProgressMonitor.INSTANCE, out, data); MultiPackIndex midx = MultiPackIndexLoader .read(new ByteArrayInputStream(out.toByteArray())); @@ -662,21 +661,16 @@ private static void assertEntry(MultiPackIndex.MutableEntry e, String oid, assertEquals(expectedOffset, e.packOffset.getOffset()); } - private static LinkedHashMap orderedMapOf(String s1, - PackIndex pi1, String s2, PackIndex pi2) { - LinkedHashMap map = new LinkedHashMap<>(2); - map.put(s1, pi1); - map.put(s2, pi2); - return map; + private static PackIndexMerger midxDataFor(String s1, PackIndex pi1, + String s2, PackIndex pi2) { + return PackIndexMerger.builder().addPack(s1, pi1).addPack(s2, pi2) + .build(); } - private static LinkedHashMap orderedMapOf(String s1, + private static PackIndexMerger midxDataFor(String s1, PackIndex pi1, String s2, PackIndex pi2, String s3, PackIndex pi3) { - LinkedHashMap map = new LinkedHashMap<>(3); - map.put(s1, pi1); - map.put(s2, pi2); - map.put(s3, pi3); - return map; + return PackIndexMerger.builder().addPack(s1, pi1).addPack(s2, pi2) + .addPack(s3, pi3).build(); } private static ObjectId oid(String last3chars) { 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 index 5971dcebf30..1743fb0e06d 100644 --- 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 @@ -23,7 +23,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedHashMap; import java.util.List; import org.eclipse.jgit.internal.storage.file.PackIndex; @@ -47,9 +46,9 @@ public void write_allSmallOffsets() throws IOException { object("0000000000000000000000000000000000000004", 1500), object("0000000000000000000000000000000000000006", 3000)); - LinkedHashMap data = new LinkedHashMap<>(); - data.put("packname1", index1); - data.put("packname2", index2); + PackIndexMerger data = PackIndexMerger.builder() + .addPack("packname1", index1).addPack("packname2", index2) + .build(); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -85,9 +84,9 @@ public void write_smallOffset_limit() throws IOException { object("0000000000000000000000000000000000000002", 500), object("0000000000000000000000000000000000000004", 1500), object("0000000000000000000000000000000000000006", 3000)); - LinkedHashMap data = new LinkedHashMap<>(2); - data.put("packname1", index1); - data.put("packname2", index2); + PackIndexMerger data = PackIndexMerger.builder() + .addPack("packname1", index1).addPack("packname2", index2) + .build(); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -122,9 +121,9 @@ public void write_largeOffset() throws IOException { object("0000000000000000000000000000000000000002", 500), object("0000000000000000000000000000000000000004", 1500), object("0000000000000000000000000000000000000006", 3000)); - LinkedHashMap data = new LinkedHashMap<>(2); - data.put("bbbbbbbbb", index1); - data.put("aaaaaaaaa", index2); + PackIndexMerger data = PackIndexMerger.builder() + .addPack("bbbbbbbbb", index1).addPack("aaaaaaaaa", index2) + .build(); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -159,9 +158,8 @@ public void write_largeOffset() throws IOException { public void jgit_emptyMidx() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - LinkedHashMap packs = new LinkedHashMap<>(2); - packs.put("p1", idxOne); - packs.put("p2", idxTwo); + PackIndexMerger packs = PackIndexMerger.builder().addPack("p1", idxOne) + .addPack("p2", idxTwo).build(); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -176,6 +174,18 @@ public void jgit_emptyMidx() throws IOException { assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES)); } + @Test + public void jgit_noPacks() throws IOException { + PackIndexMerger packs = PackIndexMerger.builder().build(); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + MultiPackIndexWriter.Result result = writer + .write(NullProgressMonitor.INSTANCE, out, packs); + assertEquals(0, result.packNames().size()); + MidxHeader header = readHeader(out); + assertEquals(0, header.packCount()); + } + private List readChunkIds(ByteArrayOutputStream out) { List chunkIds = new ArrayList<>(); byte[] raw = out.toByteArray(); @@ -195,4 +205,14 @@ private static PackIndex indexOf(IndexObject... objs) { private static IndexObject object(String name, long offset) { return new IndexObject(name, offset); } + + private record MidxHeader(int packCount) { + } + + private MidxHeader readHeader(ByteArrayOutputStream out) { + byte[] midx = out.toByteArray(); + + int packCount = NB.decodeInt32(midx, 8); + return new MidxHeader(packCount); + } } 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 index a43992d70e0..971087ee9e9 100644 --- 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 @@ -14,19 +14,23 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Arrays; import java.util.Iterator; -import java.util.LinkedHashMap; import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.MutableEntry; import org.eclipse.jgit.junit.FakeIndexFactory; import org.eclipse.jgit.junit.FakeIndexFactory.IndexObject; +import org.eclipse.jgit.lib.NullProgressMonitor; import org.junit.Test; public class PackIndexMergerTest { @Test - public void rawIterator_noDuplicates() { + public void bySha1Iterator_noDuplicates() { PackIndex idxOne = indexOf( oidOffset("0000000000000000000000000000000000000001", 500), oidOffset("0000000000000000000000000000000000000005", 12), @@ -39,12 +43,12 @@ public void rawIterator_noDuplicates() { oidOffset("0000000000000000000000000000000000000004", 502), oidOffset("0000000000000000000000000000000000000007", 14), oidOffset("0000000000000000000000000000000000000012", 1502)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxTwo, + "p3", idxThree); assertEquals(9, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); - Iterator it = merger.rawIterator(); + Iterator it = merger.bySha1Iterator(); assertNextEntry(it, "0000000000000000000000000000000000000001", 0, 500); assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 501); assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 13); @@ -61,34 +65,35 @@ public void rawIterator_noDuplicates() { } @Test - public void rawIterator_noDuplicates_honorPackOrder() { + public void bySha1Iterator_withDuplicates() { PackIndex idxOne = indexOf( oidOffset("0000000000000000000000000000000000000001", 500), - oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000010", 1500)); PackIndex idxTwo = indexOf( oidOffset("0000000000000000000000000000000000000002", 501), oidOffset("0000000000000000000000000000000000000003", 13), + oidOffset("0000000000000000000000000000000000000005", 800), oidOffset("0000000000000000000000000000000000000015", 1501)); PackIndex idxThree = indexOf( oidOffset("0000000000000000000000000000000000000004", 502), + oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000007", 14), oidOffset("0000000000000000000000000000000000000012", 1502)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p3", idxThree, "p2", idxTwo, "p1", idxOne)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxTwo, + "p3", idxThree); assertEquals(9, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); - Iterator it = merger.rawIterator(); - assertNextEntry(it, "0000000000000000000000000000000000000001", 2, 500); + Iterator it = merger.bySha1Iterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 0, 500); assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 501); assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 13); - assertNextEntry(it, "0000000000000000000000000000000000000004", 0, 502); - assertNextEntry(it, "0000000000000000000000000000000000000005", 2, 12); - assertNextEntry(it, "0000000000000000000000000000000000000007", 0, 14); - assertNextEntry(it, "0000000000000000000000000000000000000010", 2, + assertNextEntry(it, "0000000000000000000000000000000000000004", 2, 502); + assertNextEntry(it, "0000000000000000000000000000000000000005", 1, 800); + assertNextEntry(it, "0000000000000000000000000000000000000007", 2, 14); + assertNextEntry(it, "0000000000000000000000000000000000000010", 0, 1500); - assertNextEntry(it, "0000000000000000000000000000000000000012", 0, + assertNextEntry(it, "0000000000000000000000000000000000000012", 2, 1502); assertNextEntry(it, "0000000000000000000000000000000000000015", 1, 1501); @@ -96,88 +101,54 @@ public void rawIterator_noDuplicates_honorPackOrder() { } @Test - public void rawIterator_allDuplicates() { + public void bySha1Iterator_allDuplicates() { PackIndex idxOne = indexOf( oidOffset("0000000000000000000000000000000000000001", 500), oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000010", 1500)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxOne, "p3", idxOne)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxOne, + "p3", idxOne); assertEquals(3, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); - Iterator it = merger.rawIterator(); + Iterator it = merger.bySha1Iterator(); 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() { + public void bySha1Iterator_differentIndexSizes() { PackIndex idxOne = indexOf( - oidOffset("0000000000000000000000000000000000000001", 500), - oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000010", 1500)); PackIndex idxTwo = indexOf( - oidOffset("0000000000000000000000000000000000000002", 501), - oidOffset("0000000000000000000000000000000000000003", 13), - oidOffset("0000000000000000000000000000000000000015", 1501)); + oidOffset("0000000000000000000000000000000000000002", 500), + oidOffset("0000000000000000000000000000000000000003", 12)); PackIndex idxThree = indexOf( - oidOffset("0000000000000000000000000000000000000004", 502), - oidOffset("0000000000000000000000000000000000000007", 14), - oidOffset("0000000000000000000000000000000000000012", 1502)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); - assertEquals(9, merger.getUniqueObjectCount()); + oidOffset("0000000000000000000000000000000000000004", 500), + oidOffset("0000000000000000000000000000000000000007", 12), + oidOffset("0000000000000000000000000000000000000012", 1500)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxTwo, + "p3", idxThree); + assertEquals(6, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); - Iterator 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); + Iterator 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, - 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( - orderedMapOf("p1", idxOne, "p2", idxOne, "p3", idxOne)); - assertEquals(3, merger.getUniqueObjectCount()); - assertEquals(3, merger.getPackCount()); - assertFalse(merger.needsLargeOffsetsChunk()); - Iterator 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() { + public void bySha1Iterator_withAnotherMidx() throws IOException { PackIndex idxOne = indexOf( oidOffset("0000000000000000000000000000000000000010", 1500)); PackIndex idxTwo = indexOf( @@ -187,12 +158,21 @@ public void bySha1Iterator_differentIndexSizes() { oidOffset("0000000000000000000000000000000000000004", 500), oidOffset("0000000000000000000000000000000000000007", 12), oidOffset("0000000000000000000000000000000000000012", 1500)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); - assertEquals(6, merger.getUniqueObjectCount()); - assertEquals(3, merger.getPackCount()); + MultiPackIndex midx = midxOf("one", idxOne, "two", idxTwo, "three", + idxThree); + + PackIndex idxFour = indexOf( + oidOffset("0000000000000000000000000000000000000001", 12), + oidOffset("0000000000000000000000000000000000000007", 600), + oidOffset("0000000000000000000000000000000000000015", 300)); + + PackIndexMerger merger = PackIndexMerger.builder() + .addMidx(midx.iterator()).addPack("four", idxFour).build(); + assertEquals(8, merger.getUniqueObjectCount()); + assertEquals(4, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); - Iterator it = merger.bySha1Iterator(); + Iterator it = merger.bySha1Iterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 3, 12); assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 500); assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 12); assertNextEntry(it, "0000000000000000000000000000000000000004", 2, 500); @@ -201,12 +181,13 @@ public void bySha1Iterator_differentIndexSizes() { 1500); assertNextEntry(it, "0000000000000000000000000000000000000012", 2, 1500); + assertNextEntry(it, "0000000000000000000000000000000000000015", 3, 300); assertFalse(it.hasNext()); } @Test public void merger_noIndexes() { - PackIndexMerger merger = new PackIndexMerger(new LinkedHashMap<>()); + PackIndexMerger merger = PackIndexMerger.builder().build(); assertEquals(0, merger.getUniqueObjectCount()); assertFalse(merger.needsLargeOffsetsChunk()); assertTrue(merger.getPackNames().isEmpty()); @@ -216,8 +197,8 @@ public void merger_noIndexes() { @Test public void merger_emptyIndexes() { - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", indexOf(), "p2", indexOf())); + PackIndexMerger merger = createMergerFor("p1", indexOf(), "p2", + indexOf()); assertEquals(0, merger.getUniqueObjectCount()); assertFalse(merger.needsLargeOffsetsChunk()); assertEquals(2, merger.getPackNames().size()); @@ -232,8 +213,7 @@ public void bySha1Iterator_largeOffsets_needsChunk() { oidOffset("0000000000000000000000000000000000000004", 12)); PackIndex idx2 = indexOf(oidOffset( "0000000000000000000000000000000000000003", (1L << 31) + 10)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idx1, "p2", idx2)); + PackIndexMerger merger = createMergerFor("p1", idx1, "p2", idx2); assertTrue(merger.needsLargeOffsetsChunk()); assertEquals(2, merger.getOffsetsOver31BitsCount()); assertEquals(3, merger.getUniqueObjectCount()); @@ -248,8 +228,7 @@ public void bySha1Iterator_largeOffsets_noChunk() { oidOffset("0000000000000000000000000000000000000004", 12)); PackIndex idx2 = indexOf(oidOffset( "0000000000000000000000000000000000000003", (1L << 31) + 10)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idx1, "p2", idx2)); + PackIndexMerger merger = createMergerFor("p1", idx1, "p2", idx2); assertFalse(merger.needsLargeOffsetsChunk()); assertEquals(2, merger.getOffsetsOver31BitsCount()); assertEquals(3, merger.getUniqueObjectCount()); @@ -269,8 +248,8 @@ public void getObjectsPerPack_noDuplicates() { oidOffset("0000000000000000000000000000000000000004", 502), oidOffset("0000000000000000000000000000000000000007", 14), oidOffset("0000000000000000000000000000000000000012", 1502)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxTwo, + "p3", idxThree); assertArrayEquals(new int[] { 3, 3, 3 }, merger.getObjectsPerPack()); } @@ -285,8 +264,8 @@ public void getObjectsPerPack_differentIndexSizes() { oidOffset("0000000000000000000000000000000000000004", 500), oidOffset("0000000000000000000000000000000000000007", 12), oidOffset("0000000000000000000000000000000000000012", 1500)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxTwo, + "p3", idxThree); assertArrayEquals(new int[] { 1, 2, 3 }, merger.getObjectsPerPack()); } @@ -296,29 +275,28 @@ public void getObjectsPerPack_allDuplicates() { oidOffset("0000000000000000000000000000000000000001", 500), oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000010", 1500)); - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", idxOne, "p2", idxOne, "p3", idxOne)); + PackIndexMerger merger = createMergerFor("p1", idxOne, "p2", idxOne, + "p3", idxOne); assertArrayEquals(new int[] { 3, 0, 0 }, merger.getObjectsPerPack()); } @Test public void getObjectsPerPack_noIndexes() { - PackIndexMerger merger = new PackIndexMerger(new LinkedHashMap<>()); + PackIndexMerger merger = PackIndexMerger.builder().build(); assertArrayEquals(new int[] {}, merger.getObjectsPerPack()); } @Test public void getObjectsPerPack_emptyIndexes() { - PackIndexMerger merger = new PackIndexMerger( - orderedMapOf("p1", indexOf(), "p2", indexOf())); + PackIndexMerger merger = createMergerFor("p1", indexOf(), "p2", + indexOf()); assertArrayEquals(new int[] { 0, 0 }, merger.getObjectsPerPack()); } - private static void assertNextEntry( - Iterator it, String oid, + private static void assertNextEntry(Iterator it, String oid, int packId, long offset) { assertTrue(it.hasNext()); - PackIndexMerger.MidxMutableEntry e = it.next(); + MutableEntry e = it.next(); assertEquals(oid, e.getObjectId().name()); assertEquals(packId, e.getPackId()); assertEquals(offset, e.getOffset()); @@ -332,21 +310,28 @@ private static PackIndex indexOf(IndexObject... objs) { return FakeIndexFactory.indexOf(Arrays.asList(objs)); } - private static LinkedHashMap orderedMapOf(String s1, - PackIndex pi1, String s2, PackIndex pi2) { - LinkedHashMap map = new LinkedHashMap(3); - map.put(s1, pi1); - map.put(s2, pi2); - return map; - } + private static MultiPackIndex midxOf(String s1, PackIndex idx1, String s2, + PackIndex idx2, String s3, PackIndex idx3) throws IOException { + PackIndexMerger merger = createMergerFor(s1, idx1, s2, idx2, s3, idx3); + MultiPackIndexWriter w = new MultiPackIndexWriter(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + w.write(NullProgressMonitor.INSTANCE, out, merger); + + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + return MultiPackIndexLoader.read(in); + } + + private static PackIndexMerger createMergerFor(String s1, PackIndex pi1, + String s2, PackIndex pi2) { + return PackIndexMerger.builder().addPack(s1, pi1).addPack(s2, pi2) + .build(); + } - private static LinkedHashMap orderedMapOf(String s1, - PackIndex pi1, String s2, PackIndex pi2, String s3, PackIndex pi3) { - LinkedHashMap map = new LinkedHashMap(3); - map.put(s1, pi1); - map.put(s2, pi2); - map.put(s3, pi3); - return map; - } + private static PackIndexMerger createMergerFor(String s1, PackIndex pi1, + String s2, PackIndex pi2, String s3, PackIndex pi3) { + return PackIndexMerger.builder().addPack(s1, pi1).addPack(s2, pi2) + .addPack(s3, pi3).build(); + } } 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 deleted file mode 100644 index 0b3ccacfc11..00000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexPeekIteratorTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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/transport/connectivity/TreeWalkConnectivityCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityCheckerTest.java new file mode 100644 index 00000000000..371f876204e --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityCheckerTest.java @@ -0,0 +1,1129 @@ +/* + * Copyright (C) 2026, 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.internal.transport.connectivity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +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.Set; + +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdSubclassMap; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.lib.TreeFormatter; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ConnectivityChecker.ConnectivityCheckInfo; +import org.eclipse.jgit.transport.PackParser; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingFile; + +/** Tests for {@link TreeWalkConnectivityChecker}. */ +public class TreeWalkConnectivityCheckerTest { + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + private TestRepository tr; + + private TreeWalkConnectivityChecker checker; + + private ConnectivityCheckInfo info; + + private Set haves; + + private CountingProgressMonitor pm = new CountingProgressMonitor(); + + private static class CountingProgressMonitor implements ProgressMonitor { + private long objectsCheckedCount = 0; + + @Override + public void start(int totalTasks) { + // noop + } + + @Override + public void beginTask(String title, int totalWork) { + // noop + } + + @Override + public void update(int completed) { + objectsCheckedCount += completed; + } + + @Override + public void endTask() { + // noop + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public void showDuration(boolean show) { + // noop + } + + public long getObjectsCheckedCount() { + return objectsCheckedCount; + } + + public void reset() { + objectsCheckedCount = 0; + } + } + + @Mock + private PackParser parser; + + @Before + @SuppressWarnings("boxing") + public void setUp() throws Exception { + tr = new TestRepository<>( + new InMemoryRepository(new DfsRepositoryDescription("test"))); + checker = new TreeWalkConnectivityChecker(); + info = new ConnectivityCheckInfo(); + info.setRepository(tr.getRepository()); + info.setWalk(tr.getRevWalk()); + info.setParser(parser); + when(parser.needNewObjectIds()).thenReturn(true); + haves = new HashSet<>(); + pm.reset(); + } + + @Test + public void testFailureMissingParent() throws Exception { + ObjectId missingParentId = ObjectId + .fromString("0123456789abcdef0123456789abcdef01234567"); + + RevCommit newCommit = createCommitWithParent(missingParentId); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit); + + // MOE thrown within RevWalk.next() when emitting newCommit, count isn't + // updated + runCheckAndExpectMissingObject(missingParentId, 0); + } + + @Test + public void testFailureMissingParentChain() throws Exception { + ObjectId missingParentId = ObjectId + .fromString("0123456789abcdef0123456789abcdef01234567"); + + RevCommit commit1 = createCommitWithParent(missingParentId); + RevCommit commit2 = createCommitWithParent(commit1); + + setupSingleReceiveCommand(ObjectId.zeroId(), commit2.getId()); + mockNewPackObjects(commit1, commit2); + + runCheckAndExpectMissingObject(missingParentId, 1); + } + + @Test + public void testFailureMissingParentMultipleBranches() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + ObjectId missingParentId = ObjectId + .fromString("0123456789abcdef0123456789abcdef01234567"); + + RevCommit newCommit1 = tr.commit().parent(base).create(); + RevCommit newCommit2 = createCommitWithParent(missingParentId); + + ReceiveCommand cmd1 = new ReceiveCommand(base, newCommit1, + "refs/heads/branch1"); + ReceiveCommand cmd2 = new ReceiveCommand(ObjectId.zeroId(), newCommit2, + "refs/heads/branch2"); + + info.setCommands(Arrays.asList(cmd1, cmd2)); + + mockNewPackObjects(newCommit1, newCommit2); + + runCheckAndExpectMissingObject(missingParentId, 1); + } + + @Test + public void testFailureMissingBlob() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + // Create a missing blob ID that is not in DB or pack + ObjectId missingBlobId = ObjectId + .fromString("0123456789abcdef0123456789abcdef01234567"); + RevBlob missingBlob = tr.getRevWalk().lookupBlob(missingBlobId); + + RevCommit newCommit = tr.commit().parent(base).add("foo", missingBlob) + .create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndExpectMissingObject(missingBlobId, 4); + } + + @Test + public void testFailureMissingSubtree() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + ObjectId missingTreeId = ObjectId + .fromString("0123456789abcdef0123456789abcdef01234568"); + + RevBlob blob = tr.blob("content"); + + TreeFormatter formatter = new TreeFormatter(); + formatter.append("file", FileMode.REGULAR_FILE, blob); + formatter.append("dir", FileMode.TREE, missingTreeId); + + try (ObjectInserter inserter = tr.getRepository().newObjectInserter()) { + ObjectId rootTreeId = inserter.insert(formatter); + + CommitBuilder cb = new CommitBuilder(); + cb.setTreeId(rootTreeId); + cb.setAuthor(new PersonIdent("Author", "author@example.com")); + cb.setCommitter( + new PersonIdent("Committer", "committer@example.com")); + cb.setMessage("Commit with missing subtree"); + cb.setParentIds(base.getId()); + + ObjectId commitId = inserter.insert(cb); + inserter.flush(); + + RevCommit newCommit = tr.getRevWalk().parseCommit(commitId); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree(), blob); + + runCheckAndExpectMissingObject(missingTreeId, 4); + } + } + + @Test + public void testFailureUnreachableParentCommit() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevCommit secretCommit = tr.commit().create(); + RevCommit newCommit = tr.commit().parent(secretCommit).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndExpectMissingObject(secretCommit.getId(), 3); + } + + @Test + public void testMultipleBranchesUnreachableParent() throws Exception { + // base2 & new2 have newer timestamps + RevCommit base1 = tr.commit().create(); + RevCommit new1 = tr.commit().parent(base1).create(); + RevCommit base2 = tr.commit().create(); + RevCommit new2 = tr.commit().parent(base2).create(); + + tr.branch("refs/heads/base1").update(base1); + haves.add(base1); + + ReceiveCommand cmd1 = new ReceiveCommand(base1, new1, "refs/heads/b1"); + ReceiveCommand cmd2 = new ReceiveCommand(base2, new2, "refs/heads/b2"); + + info.setCommands(Arrays.asList(cmd1, cmd2)); + mockNewPackObjects(new1, new1.getTree(), new2, new2.getTree()); + + runCheckAndExpectMissingObject(base2, 5); + + // Verify order doesn't matter - reset state and swap order + setUp(); + + // base2 & new2 have newer timestamps + base1 = tr.commit().create(); + new1 = tr.commit().parent(base1).create(); + base2 = tr.commit().create(); + new2 = tr.commit().parent(base2).create(); + + tr.branch("refs/heads/base2").update(base2); + haves.add(base2); + + cmd1 = new ReceiveCommand(base1, new1, "refs/heads/b1"); + cmd2 = new ReceiveCommand(base2, new2, "refs/heads/b2"); + + info.setCommands(Arrays.asList(cmd2, cmd1)); + mockNewPackObjects(new1, new1.getTree(), new2, new2.getTree()); + + runCheckAndExpectMissingObject(base1, 5); + } + + @Test + public void testThinPackFailureUnreachableDeltaBase() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob deltafiledBlob = tr.blob("simulated delta blob"); + RevBlob missingBase = tr.getRevWalk().lookupBlob(ObjectId + .fromString("0123456789abcdef0123456789abcdef01234567")); + RevCommit newCommit = tr.commit().parent(base) + .add("foo", deltafiledBlob).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit); + mockNewPackObjects(newCommit, newCommit.getTree(), deltafiledBlob); + + ObjectIdSubclassMap baseObjectIds = new ObjectIdSubclassMap<>(); + baseObjectIds.add(missingBase); + when(parser.getBaseObjectIds()).thenReturn(baseObjectIds); + info.setCheckObjects(true); + + runCheckAndExpectMissingObject(missingBase.getId(), 2); + } + + @Test + public void testSuccessMatchingParent() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + // Create a new commit in the pack that explicitly matches the base tree + ObjectId newCommitId = tr.unparsedCommit(1, base.getTree(), + base.getId()); + RevCommit newCommit = tr.getRevWalk().parseCommit(newCommitId); + + setupSingleReceiveCommand(base.getId(), newCommitId); + mockNewPackObjects(newCommit); + runCheckAndAssertCount(4); + } + + @Test + public void testSuccessWithDifferentBlob() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob blob = tr.blob("hello"); + RevCommit newCommit = tr.commit().parent(base).add("foo", blob) + .create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree(), blob); + + runCheckAndAssertCount(4); + } + + @Test + public void testSuccessNoReachabilityCheckWhenParentsInHaves() + throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevCommit currentHaves = base; + for (int i = 0; i < 250; i++) { + currentHaves = tr.commit().parent(currentHaves).create(); + haves.add(currentHaves.getId()); + } + + RevBlob blob = tr.blob("hello"); + RevCommit newCommit = tr.commit().parent(base).add("foo", blob) + .create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit); + + runCheckAndAssertCount(4); + } + + /** + * Test with a large flat tree to measure objects checked. + * + *

{@code
+	 * [Existing DB]               [Received Pack]
+	 *      base <------------------- newCommit
+	 *        |                          |
+	 *      root_tree                 root_tree (differs)
+	 *        |                          |
+	 *        +- file0                   +- file0 (differs)
+	 *        +- file1                   +- file1 (differs)
+	 *        +- file2                   +- file2 (differs)
+	 *        +- file3                   +- file3 (differs)
+	 *        +- file4                   +- file4 (differs)
+	 *        +- file5                   +- file5 (shared)
+	 *        +- ...                     +- ...
+	 *        `- file99                  `- file99 (shared)
+	 * }
+ */ + @Test + public void testLargeFlatTree() throws Exception { + TestRepository.CommitBuilder cb = tr.commit(); + for (int i = 0; i < 100; i++) { + cb.add("file" + i, tr.blob("content" + i)); + } + RevCommit base = cb.create(); + haves.add(base.getId()); + + TestRepository.CommitBuilder cbNew = tr.commit().parent(base); + List allNewObjects = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + RevBlob b = tr.blob("new content " + i); + cbNew.add("file" + i, b); + allNewObjects.add(b); + } + RevCommit newCommit = cbNew.create(); + allNewObjects.add(newCommit); + allNewObjects.add(newCommit.getTree()); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(allNewObjects); + + runCheckAndAssertCount(4); + } + + @Test + public void testGitlink() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + ObjectId submoduleCommitId = ObjectId + .fromString("0123456789abcdef0123456789abcdef01234567"); + + TreeFormatter formatter = new TreeFormatter(); + formatter.append("submodule", FileMode.GITLINK, submoduleCommitId); + + try (ObjectInserter inserter = tr.getRepository().newObjectInserter()) { + ObjectId rootTreeId = inserter.insert(formatter); + + CommitBuilder cb = new CommitBuilder(); + cb.setTreeId(rootTreeId); + cb.setAuthor(new PersonIdent("Author", "author@example.com")); + cb.setCommitter( + new PersonIdent("Committer", "committer@example.com")); + cb.setMessage("Commit with gitlink"); + cb.setParentIds(base.getId()); + + ObjectId commitId = inserter.insert(cb); + inserter.flush(); + + RevCommit newCommit = tr.getRevWalk().parseCommit(commitId); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + // Should not fail gitlink identifier not being in the local + // database + runCheckAndAssertCount(4); + } + } + + @Test + public void testZeroParents() throws Exception { + RevBlob blob = tr.blob("content"); + RevCommit rootCommit = tr.commit().add("file1", blob).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), rootCommit.getId()); + mockNewPackObjects(rootCommit, rootCommit.getTree(), blob); + + runCheckAndAssertCount(2); + } + + @Test + public void testMultipleParents() throws Exception { + RevCommit parent1 = tr.commit().add("file1", tr.blob("content1")) + .create(); + RevCommit parent2 = tr.commit().add("file2", tr.blob("content2")) + .create(); + haves.add(parent1.getId()); + haves.add(parent2.getId()); + + RevCommit mergeCommit = tr.commit().parent(parent1).parent(parent2) + .add("file3", tr.blob("content3")).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), mergeCommit.getId()); + mockNewPackObjects(mergeCommit, mergeCommit.getTree()); + + runCheckAndAssertCount(6); + } + + @Test + public void testChainedCommitsInPack() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevCommit c1 = tr.commit().parent(base).create(); + RevCommit c2 = tr.commit().parent(c1).create(); + + setupSingleReceiveCommand(base.getId(), c2.getId()); + mockNewPackObjects(c1, c2, c1.getTree(), c2.getTree()); + + runCheckAndAssertCount(7); + } + + @Test + public void testSuccessReachableParentCommit() throws Exception { + RevCommit base = tr.commit().create(); + RevCommit reachableCommit = tr.commit().parent(base).create(); + haves.add(reachableCommit.getId()); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(5); + } + + @Test + public void testSuccessFallbackToFullRefDatabase() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevCommit newRootCommit = tr.commit().create(); + tr.branch("refs/heads/unconnected").update(newRootCommit); + + RevCommit newCommit = tr.commit().parent(newRootCommit).create(); + + info.setCommands(Collections.singletonList(new ReceiveCommand( + ObjectId.zeroId(), newCommit.getId(), "refs/heads/master"))); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(5); + } + + @Test + public void testCheckReachabilityWithBlobInHaves() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob blob = tr.blob("blob content"); + haves.add(blob.getId()); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(4); + } + + @Test + public void testCheckReachabilityWithAnnotatedTagInHaves() + throws Exception { + RevCommit base = tr.commit().create(); + + RevTag tag = tr.tag("my-tag", base); + haves.add(tag.getId()); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(5); + } + + @Test + public void testCheckReachabilityWithBlobInRefs() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob blob = tr.blob("blob content"); + tr.update("refs/tags/my-blob", blob); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(4); + } + + @Test + public void testCheckReachabilityWithAnnotatedTagInRefs() throws Exception { + RevCommit base = tr.commit().create(); + + RevTag tag = tr.tag("my-tag", base); + tr.update("refs/tags/my-tag", tag); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(4); + } + + @Test + public void testSuccessWithDeletion() throws Exception { + RevBlob blob = tr.blob("hello"); + RevCommit base = tr.commit().add("foo", blob).create(); + haves.add(base.getId()); + + // Create a new commit that deletes "foo" + RevCommit newCommit = tr.commit().parent(base).rm("foo").create(); + + info.setCommands(Collections.singletonList(new ReceiveCommand( + base.getId(), newCommit.getId(), "refs/heads/master"))); + + mockNewPackObjects(newCommit, newCommit.getTree()); + + runCheckAndAssertCount(4); + } + + @Test + public void testDeleteCommandIgnored() throws Exception { + RevCommit base = tr.commit().create(); + tr.branch("refs/heads/master").update(base); + + ReceiveCommand cmd = new ReceiveCommand(base.getId(), ObjectId.zeroId(), + "refs/heads/master", ReceiveCommand.Type.DELETE); + + info.setCommands(Collections.singletonList(cmd)); + + runCheckAndAssertCount(0); + } + + @Test + public void testMultipleCommands() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob blob1 = tr.blob("content1"); + RevCommit newCommit1 = tr.commit().parent(base).add("foo1", blob1) + .create(); + + RevBlob blob2 = tr.blob("content2"); + RevCommit newCommit2 = tr.commit().parent(base).add("foo2", blob2) + .create(); + + ReceiveCommand cmd1 = new ReceiveCommand(base.getId(), + newCommit1.getId(), "refs/heads/branch1"); + ReceiveCommand cmd2 = new ReceiveCommand(base.getId(), + newCommit2.getId(), "refs/heads/branch2"); + + info.setCommands(Arrays.asList(cmd1, cmd2)); + + mockNewPackObjects(newCommit1, newCommit1.getTree(), blob1, newCommit2, + newCommit2.getTree(), blob2); + + runCheckAndAssertCount(7); + } + + @Test + public void testThinPackSuccess() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob baseBlob = tr.blob("base blob content"); + haves.add(baseBlob.getId()); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + ObjectIdSubclassMap baseObjectIds = new ObjectIdSubclassMap<>(); + baseObjectIds.add(baseBlob.getId()); + when(parser.getBaseObjectIds()).thenReturn(baseObjectIds); + info.setCheckObjects(true); + + runCheckAndAssertCount(4); + } + + @Test + public void testThinPackWithBlobInHaves() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob baseBlob = tr.blob("base blob content"); + + RevBlob unrelatedBlob = tr.blob("unrelated blob content"); + haves.add(unrelatedBlob.getId()); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + ObjectIdSubclassMap baseObjectIds = new ObjectIdSubclassMap<>(); + baseObjectIds.add(baseBlob.getId()); + when(parser.getBaseObjectIds()).thenReturn(baseObjectIds); + info.setCheckObjects(true); + + runCheckAndAssertCount(4); + } + + @Test + public void testThinPackWithSignedTagInHaves() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob baseBlob = tr.blob("base blob content"); + + RevTag tag = tr.tag("my-tag", base); + haves.add(tag.getId()); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + ObjectIdSubclassMap baseObjectIds = new ObjectIdSubclassMap<>(); + baseObjectIds.add(baseBlob.getId()); + when(parser.getBaseObjectIds()).thenReturn(baseObjectIds); + info.setCheckObjects(true); + + runCheckAndAssertCount(4); + } + + @Test + public void testThinPackWithBlobInRefs() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob baseBlob = tr.blob("base blob content"); + + RevBlob unrelatedBlob = tr.blob("unrelated blob content"); + tr.update("refs/tags/my-blob", unrelatedBlob); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + ObjectIdSubclassMap baseObjectIds = new ObjectIdSubclassMap<>(); + baseObjectIds.add(baseBlob.getId()); + when(parser.getBaseObjectIds()).thenReturn(baseObjectIds); + info.setCheckObjects(true); + + runCheckAndAssertCount(4); + } + + @Test + public void testThinPackWithAnnotatedTagInRefs() throws Exception { + RevCommit base = tr.commit().create(); + haves.add(base.getId()); + + RevBlob baseBlob = tr.blob("base blob content"); + + RevTag tag = tr.tag("my-tag", base); + tr.update("refs/tags/my-tag", tag); + + RevCommit newCommit = tr.commit().parent(base).create(); + + setupSingleReceiveCommand(base.getId(), newCommit.getId()); + mockNewPackObjects(newCommit, newCommit.getTree()); + + ObjectIdSubclassMap baseObjectIds = new ObjectIdSubclassMap<>(); + baseObjectIds.add(baseBlob.getId()); + when(parser.getBaseObjectIds()).thenReturn(baseObjectIds); + info.setCheckObjects(true); + + runCheckAndAssertCount(4); + } + + @Test + public void testMultipleCommandsDifferentParents() throws Exception { + RevCommit base1 = tr.commit().create(); + RevCommit base2 = tr.commit().create(); + tr.branch("refs/heads/base1").update(base1); + tr.branch("refs/heads/base2").update(base2); + haves.add(base1.getId()); + haves.add(base2.getId()); + + RevBlob blob1 = tr.blob("content1"); + RevCommit newCommit1 = tr.commit().parent(base1).add("foo1", blob1) + .create(); + + RevBlob blob2 = tr.blob("content2"); + RevCommit newCommit2 = tr.commit().parent(base2).add("foo2", blob2) + .create(); + + ReceiveCommand cmd1 = new ReceiveCommand(base1.getId(), + newCommit1.getId(), "refs/heads/branch1"); + ReceiveCommand cmd2 = new ReceiveCommand(base2.getId(), + newCommit2.getId(), "refs/heads/branch2"); + + info.setCommands(Arrays.asList(cmd1, cmd2)); + + mockNewPackObjects(newCommit1, newCommit1.getTree(), blob1, newCommit2, + newCommit2.getTree(), blob2); + + runCheckAndAssertCount(8); + } + + /** + * Test case with a deep and wide tree structure. Modifying a file 5 levels + * deep should only check the trees along that path. + * + *
{@code
+	 * [Existing DB]               [Received Pack]
+	 *      base <------------------- newCommit
+	 *        |                          |
+	 *      root_tree                 root_tree (differs)
+	 *        |                          |
+	 *        +- A                       +- A (differs)
+	 *        |  +- C                    |  +- C (differs)
+	 *        |  |  +- I                 |  |  +- I (differs)
+	 *        |  |  |  +- J              |  |  |  +- J (differs)
+	 *        |  |  |  |  +- K           |  |  |  |  +- K (differs)
+	 *        |  |  |  |  |  +- L        |  |  |  |  |  +- L (differs)
+	 *        |  |  |  |  |  |  +- M     |  |  |  |  |  |  +- M (differs)
+	 *        |  |  |  |  |  |  |  `- 1  |  |  |  |  |  |  |  `- 1 (differs)
+	 *        |  +- D                    |  +- D (shared)
+	 *        |     `- 2                 |     `- 2 (shared)
+	 *        +- B                       +- B (shared)
+	 *           +- E                    |  +- E (shared)
+	 *           |  `- 3                 |     `- 3 (shared)
+	 *           +- F                    |  +- F (shared)
+	 *           |  `- 4                 |     `- 4 (shared)
+	 *           +- G                    |  +- G (shared)
+	 *           |  `- 5                 |     `- 5 (shared)
+	 *           +- H                    |  +- H (shared)
+	 *              `- 6                 |     `- 6 (shared)
+	 * }
+ */ + @Test + public void testDeepTreeSuccess() throws Exception { + // Create base with deep and wide structure + TestRepository.CommitBuilder cb = tr.commit(); + cb.add("A/C/I/J/K/L/M/1", tr.blob("content1")); + cb.add("A/D/2", tr.blob("content2")); + cb.add("B/E/3", tr.blob("content3")); + cb.add("B/F/4", tr.blob("content4")); + cb.add("B/G/5", tr.blob("content5")); + cb.add("B/H/6", tr.blob("content6")); + RevCommit base = cb.create(); + haves.add(base.getId()); + + RevCommit currentHaves = base; + for (int i = 0; i < 250; i++) { + currentHaves = tr.commit().parent(currentHaves).create(); + haves.add(currentHaves.getId()); + } + + // Create new commit modifying file at end of deep path + RevBlob newBlob = tr.blob("new content"); + RevCommit newCommit = tr.commit().parent(base) + .add("A/C/I/J/K/L/M/000", newBlob).create(); + + info.setCommands(Collections.singletonList(new ReceiveCommand( + base.getId(), newCommit.getId(), "refs/heads/master"))); + + List allNewObjects = new ArrayList<>(); + allNewObjects.add(newCommit); + allNewObjects.add(newCommit.getTree()); + allNewObjects.add(newBlob); + try (TreeWalk tw = new TreeWalk(tr.getRepository())) { + tw.setRecursive(false); + tw.addTree(newCommit.getTree()); + String[] pathSegments = { "A", "C", "I", "J", "K", "L", "M" }; + for (String segment : pathSegments) { + while (tw.next()) { + if (tw.getNameString().equals(segment)) { + allNewObjects.add(tw.getObjectId(0)); + tw.enterSubtree(); + break; + } + } + } + } + mockNewPackObjects(allNewObjects); + + runCheckAndAssertCount(18); + } + + /** + * Compare the efficiency of the TreeWalk checker vs. iterative vs. full + * checkers. Initial JFR results on this test: + *
    + *
  • TreeWalk Checker: 22 checked objects, 25 JFR allocations
  • + *
  • Iterative Checker: 14 checked objects, 41 JFR allocations
  • + *
  • Full Checker: 264 checked objects, 147 JFR allocations
  • + *
+ * + *
{@code
+	 * [Existing DB]               [Received Pack]
+	 *      base <------------------- newCommit
+	 *        |                          |
+	 *      root_tree                 root_tree (differs)
+	 *        |                          |
+	 *        +- A                       +- A (differs)
+	 *        |  +- C                    |  +- C (differs)
+	 *        |  |  +- I                 |  |  +- I (differs)
+	 *        |  |  |  +- J              |  |  |  +- J (differs)
+	 *        |  |  |  |  +- K           |  |  |  |  +- K (differs)
+	 *        |  |  |  |  |  +- L        |  |  |  |  |  +- L (differs)
+	 *        |  |  |  |  |  |  +- M     |  |  |  |  |  |  +- M (differs)
+	 *        |  |  |  |  |  |  |  `- 1  |  |  |  |  |  |  |  `- 1 (differs)
+	 *        |  +- D                    |  +- D (shared)
+	 *        |     `- 2                 |     `- 2 (shared)
+	 *        +- B                       +- B (differs)
+	 *           +- E                    |  +- E (shared)
+	 *           |  `- 3                 |     `- 3 (shared)
+	 *           +- F                    |  +- F (shared)
+	 *           |  `- 4                 |     `- 4 (shared)
+	 *           +- G                    |  +- G (shared)
+	 *           |  `- 5                 |     `- 5 (shared)
+	 *           +- H                    |  +- H (differs)
+	 *              `- 6                 |     `- 6 (differs)
+	 * }
+ */ + @Test + public void testDeepTreePerformance() throws Exception { + // Create base with deep and wide structure + TestRepository.CommitBuilder cb = tr.commit(); + cb.add("A/C/I/J/K/L/M/1", tr.blob("content1")); + cb.add("A/D/2", tr.blob("content2")); + cb.add("B/E/3", tr.blob("content3")); + cb.add("B/F/4", tr.blob("content4")); + cb.add("B/G/5", tr.blob("content5")); + cb.add("B/H/6", tr.blob("content6")); + + RevCommit base = cb.create(); + haves.add(base.getId()); + RevCommit currentHaves = base; + for (int i = 0; i < 250; i++) { + currentHaves = tr.commit().parent(currentHaves).create(); + haves.add(currentHaves.getId()); + } + + // Create new commit modifying file at end of deep path + RevBlob newBlob = tr.blob("new content"); + RevCommit newCommit = tr.commit().parent(base) + .add("A/C/I/J/K/L/M/1", newBlob).add("B/H/6", newBlob).create(); + + info.setCommands(Collections.singletonList(new ReceiveCommand( + base.getId(), newCommit.getId(), "refs/heads/new_change"))); + + ObjectIdSubclassMap newObjectIds = new ObjectIdSubclassMap<>(); + newObjectIds.add(newCommit); + newObjectIds.add(newCommit.getTree()); + newObjectIds.add(newBlob); + try (TreeWalk tw = new TreeWalk(tr.getRepository())) { + tw.setRecursive(false); + tw.addTree(newCommit.getTree()); + String[] pathSegments = { "A", "C", "I", "J", "K", "L", "M" }; + for (String segment : pathSegments) { + while (tw.next()) { + if (tw.getNameString().equals(segment)) { + newObjectIds.add(tw.getObjectId(0)); + tw.enterSubtree(); + break; + } + } + } + } + try (TreeWalk tw = new TreeWalk(tr.getRepository())) { + tw.setRecursive(false); + tw.addTree(newCommit.getTree()); + while (tw.next()) { + if (tw.getNameString().equals("B")) { + newObjectIds.add(tw.getObjectId(0)); + tw.enterSubtree(); + while (tw.next()) { + if (tw.getNameString().equals("H")) { + newObjectIds.add(tw.getObjectId(0)); + break; + } + } + break; + } + } + } + when(parser.getNewObjectIds()).thenReturn(newObjectIds); + + TreeWalkConnectivityChecker scChecker = new TreeWalkConnectivityChecker(); + + long scJfrCount = 0; + try (Recording r = new Recording()) { + r.enable("jdk.ObjectAllocationInNewTLAB"); + r.enable("jdk.ObjectAllocationOutsideTLAB"); + r.start(); + + for (int i = 0; i < 1000; i++) { + try (RevWalk rw = new RevWalk(info.getRepository())) { + info.setWalk(rw); + pm.reset(); + scChecker.checkConnectivity(info, haves, pm); + } + } + + r.stop(); + Path p = Files.createTempFile("sc_jfr", ".jfr"); + r.dump(p); + try (RecordingFile file = new RecordingFile(p)) { + while (file.hasMoreEvents()) { + file.readEvent(); + scJfrCount++; + } + } + Files.delete(p); + } + long scCount = pm.getObjectsCheckedCount(); + + // Run IterativeConnectivityChecker + IterativeConnectivityChecker icChecker = new IterativeConnectivityChecker( + new FullConnectivityChecker()); + + long icJfrCount = 0; + try (jdk.jfr.Recording r = new jdk.jfr.Recording()) { + r.enable("jdk.ObjectAllocationInNewTLAB"); + r.enable("jdk.ObjectAllocationOutsideTLAB"); + r.start(); + + for (int i = 0; i < 1000; i++) { + try (RevWalk rw = new RevWalk(info.getRepository())) { + info.setWalk(rw); + pm.reset(); + icChecker.checkConnectivity(info, haves, pm); + } + } + + r.stop(); + Path p = Files.createTempFile("ic_jfr_deep", ".jfr"); + r.dump(p); + try (jdk.jfr.consumer.RecordingFile file = new jdk.jfr.consumer.RecordingFile( + p)) { + while (file.hasMoreEvents()) { + jdk.jfr.consumer.RecordedEvent event = file.readEvent(); + if (event.getEventType().getName() + .startsWith("jdk.ObjectAllocation")) { + icJfrCount++; + } + } + } + Files.delete(p); + } + long icCount = pm.getObjectsCheckedCount(); + + // Run FullConnectivityChecker + FullConnectivityChecker fcChecker = new FullConnectivityChecker(); + + long fcJfrCount = 0; + try (Recording r = new Recording()) { + r.enable("jdk.ObjectAllocationInNewTLAB"); + r.enable("jdk.ObjectAllocationOutsideTLAB"); + r.start(); + + for (int i = 0; i < 1000; i++) { + try (RevWalk rw = new RevWalk(info.getRepository())) { + info.setWalk(rw); + pm.reset(); + fcChecker.checkConnectivity(info, haves, pm); + } + } + + r.stop(); + Path p = Files.createTempFile("fc_jfr", ".jfr"); + r.dump(p); + try (RecordingFile file = new RecordingFile(p)) { + while (file.hasMoreEvents()) { + file.readEvent(); + fcJfrCount++; + } + } + Files.delete(p); + } + long fcCount = pm.getObjectsCheckedCount(); + + System.out.println("TreeWalk Checked Objects: " + scCount); + System.out.println("TreeWalk JFR allocations: " + scJfrCount); + System.out.println("Iterative Checked Objects: " + icCount); + System.out.println("Iterative JFR allocations: " + icJfrCount); + System.out.println("Full Checked Objects: " + fcCount); + System.out.println("Full JFR allocations: " + fcJfrCount); + + assertEquals(22, scCount); + assertEquals(14, icCount); + assertEquals(264, fcCount); + + assertTrue( + "TreeWalkConnectivityChecker should produce fewer JFR allocation events. Expected " + + scJfrCount + " < " + fcJfrCount, + scJfrCount < fcJfrCount); + } + + private void setupSingleReceiveCommand(ObjectId oldId, ObjectId newId) { + info.setCommands(Collections.singletonList( + new ReceiveCommand(oldId, newId, "refs/heads/master"))); + } + + private void mockNewPackObjects(ObjectId... ids) { + mockNewPackObjects(Arrays.asList(ids)); + } + + private void mockNewPackObjects(Collection ids) { + ObjectIdSubclassMap map = new ObjectIdSubclassMap<>(); + for (ObjectId id : ids) { + map.add(id); + } + when(parser.getNewObjectIds()).thenReturn(map); + } + + private void runCheckAndAssertCount(int expectedCount) throws IOException { + checker.checkConnectivity(info, haves, pm); + assertEquals(expectedCount, pm.getObjectsCheckedCount()); + } + + private void runCheckAndExpectMissingObject(ObjectId expectedMissingId, + int expectedCount) throws IOException { + try { + checker.checkConnectivity(info, haves, pm); + fail("Expected MissingObjectException"); + } catch (MissingObjectException e) { + assertEquals(expectedMissingId, e.getObjectId()); + assertEquals(expectedCount, pm.getObjectsCheckedCount()); + } + } + + private RevCommit createCommitWithParent(ObjectId parentId) + throws Exception { + CommitBuilder cb = new CommitBuilder(); + cb.setTreeId(tr.tree().getId()); + cb.setParentId(parentId); + cb.setAuthor(new PersonIdent("Author", "author@example.com", + tr.getInstant(), tr.getTimeZoneId())); + cb.setCommitter(new PersonIdent("Committer", "committer@example.com", + tr.getInstant(), tr.getTimeZoneId())); + cb.setMessage("Commit with specific parent"); + + try (ObjectInserter ins = tr.getRepository().newObjectInserter()) { + ObjectId id = ins.insert(cb); + ins.flush(); + return tr.getRevWalk().parseCommit(id); + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java index d64cfc53a64..b1fd58e8191 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java @@ -1996,16 +1996,18 @@ public void testLongFilename() throws Exception { break; } } - char[] bytes = new char[maximumFileNameLength]; - Arrays.fill(bytes, 'f'); - String longFileName = new String(bytes); + String longFileName = "f".repeat(maximumFileNameLength); + String longFileName2 = "ф".repeat(maximumFileNameLength / 2); // 1 - doit(mkmap(longFileName, "a"), mkmap(longFileName, "b"), - mkmap(longFileName, "a")); + doit(mkmap(longFileName, "a", longFileName2, "a"), + mkmap(longFileName, "b", longFileName2, "b"), + mkmap(longFileName, "a", longFileName2, "a")); writeTrashFile(longFileName, "a"); + writeTrashFile(longFileName2, "a"); checkout(); assertNoConflicts(); assertUpdated(longFileName); + assertUpdated(longFileName2); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java index 7f1dfc32ce7..27737154ab8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java @@ -277,6 +277,7 @@ public void invalidNames() throws AmbiguousObjectException, IOException { assertTrue(Repository.isValidRefName("x/a]b")); // odd, yes.. assertTrue(Repository.isValidRefName("x/\u00a0")); // unicode is fine, // even hard space + assertFalse(Repository.isValidRefName("single-component")); assertFalse(Repository.isValidRefName("x/.a")); assertFalse(Repository.isValidRefName("x/a.")); assertFalse(Repository.isValidRefName("x/a..b")); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java index c6a6321cf80..b5e4b2122bb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java @@ -11,6 +11,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.time.Instant.EPOCH; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -30,6 +32,7 @@ import java.util.Set; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.RebaseResult; @@ -963,6 +966,39 @@ public void checkContentMergeConflict(MergeStrategy strategy) assertEquals(expected, read("file")); } + @Theory + public void checkContentMergeConflictDiff3(MergeStrategy strategy) + throws Exception { + Git git = Git.wrap(db); + + writeTrashFile("file", "1\n2\n3"); + git.add().addFilepattern("file").call(); + RevCommit first = git.commit().setMessage("added file").call(); + + writeTrashFile("file", "1master\n2\n3"); + git.commit().setAll(true).setMessage("modified file on master").call(); + + git.checkout().setCreateBranch(true).setStartPoint(first) + .setName("side").call(); + writeTrashFile("file", "1side\n2\n3"); + RevCommit sideCommit = git.commit().setAll(true) + .setMessage("modified file on side").call(); + + git.checkout().setName("master").call(); + + db.getConfig().setEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3); + + MergeResult result = git.merge().setStrategy(strategy) + .include(sideCommit).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + String expected = "<<<<<<< HEAD\n" + "1master\n" + "||||||| BASE\n" + + "1\n" + "=======\n" + "1side\n" + ">>>>>>> " + + sideCommit.name() + "\n" + "2\n" + + "3"; + assertEquals(expected, read("file")); + } + @Theory public void checkContentMergeConflict_noTree(MergeStrategy strategy) throws Exception { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AbstractRevWalkWithCommitGraphTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AbstractRevWalkWithCommitGraphTest.java new file mode 100644 index 00000000000..4276f10543b --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AbstractRevWalkWithCommitGraphTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023, Tencent 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.revwalk; + +import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraph.EMPTY; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.storage.file.GC; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.filter.RevFilter; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.treewalk.filter.TreeFilter; + +public abstract class AbstractRevWalkWithCommitGraphTest extends RevWalkTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + reinitializeRevWalk(); + mockSystemReader.setJGitConfig(new MockConfig()); + } + + protected final void assertCommitCntInGraph(int expect) { + assertEquals(expect, rw.commitGraph().getCommitCnt()); + } + + protected final void assertCommits(List expect, + List actual) { + assertEquals(expect.size(), actual.size()); + + for (int i = 0; i < expect.size(); i++) { + RevCommit c1 = expect.get(i); + RevCommit c2 = actual.get(i); + assertEquals(c1.getId(), c2.getId()); + assertEquals(c1.getTree(), c2.getTree()); + assertEquals(c1.getCommitTime(), c2.getCommitTime()); + assertArrayEquals(c1.getParents(), c2.getParents()); + assertArrayEquals(c1.getRawBuffer(), c2.getRawBuffer()); + } + } + + protected final Ref branch(RevCommit commit, String name) throws Exception { + return Git.wrap(db).branchCreate().setName(name) + .setStartPoint(commit.name()).call(); + } + + protected final List travel(TreeFilter treeFilter, + RevFilter revFilter, RevSort revSort, boolean enableCommitGraph, + String... starts) + throws MissingObjectException, IncorrectObjectTypeException, + IOException, AmbiguousObjectException { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_COMMIT_GRAPH, enableCommitGraph); + + try (RevWalk walk = new RevWalk(db)) { + walk.setTreeFilter(treeFilter); + walk.setRevFilter(revFilter); + walk.sort(revSort); + walk.setRetainBody(false); + for (String start : starts) { + walk.markStart(walk.lookupCommit(db.resolve(start))); + } + List commits = new ArrayList<>(); + + if (enableCommitGraph) { + assertTrue(walk.commitGraph().getCommitCnt() > 0); + } else { + assertEquals(EMPTY, walk.commitGraph()); + } + + for (RevCommit commit : walk) { + commits.add(commit); + } + return commits; + } + } + + protected final void enableAndWriteCommitGraph() throws Exception { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_COMMIT_GRAPH, true); + db.getConfig().setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, + ConfigConstants.CONFIG_KEY_WRITE_COMMIT_GRAPH, true); + db.getConfig().setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, + ConfigConstants.CONFIG_KEY_WRITE_CHANGED_PATHS, true); + GC gc = new GC(db); + gc.gc().get(); + } + + protected final void reinitializeRevWalk() { + rw.close(); + rw = new RevWalk(db); + } + + private static final class MockConfig extends FileBasedConfig { + private MockConfig() { + super(null, null); + } + + @Override + public void load() throws IOException, ConfigInvalidException { + // Do nothing + } + + @Override + public void save() throws IOException { + // Do nothing + } + + @Override + public boolean isOutdated() { + return false; + } + + @Override + public String toString() { + return "MockConfig"; + } + + @Override + public boolean getBoolean(final String section, final String name, + final boolean defaultValue) { + if (section.equals(ConfigConstants.CONFIG_COMMIT_GRAPH_SECTION) + && name.equals( + ConfigConstants.CONFIG_KEY_READ_CHANGED_PATHS)) { + return true; + } + return defaultValue; + } + } + +} 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 e47dd898b06..41b2c2432cc 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 @@ -11,7 +11,6 @@ package org.eclipse.jgit.revwalk; import static java.util.Arrays.asList; -import static org.eclipse.jgit.internal.storage.commitgraph.CommitGraph.EMPTY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -20,22 +19,17 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import org.eclipse.jgit.api.Git; import org.eclipse.jgit.diff.DiffConfig; -import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.internal.storage.file.GC; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; 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; @@ -43,16 +37,7 @@ import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.junit.Test; -public class RevWalkCommitGraphTest extends RevWalkTestCase { - - private RevWalk rw; - - @Override - public void setUp() throws Exception { - super.setUp(); - rw = new RevWalk(db); - mockSystemReader.setJGitConfig(new MockConfig()); - } +public class RevWalkCommitGraphTest extends AbstractRevWalkWithCommitGraphTest { @Test public void testParseHeaders() throws Exception { @@ -60,7 +45,6 @@ public void testParseHeaders() throws Exception { RevCommit notParseInGraph = rw.lookupCommit(c1); rw.parseHeaders(notParseInGraph); - assertFalse(notParseInGraph instanceof RevCommitCG); assertNotNull(notParseInGraph.getRawBuffer()); assertEquals(Constants.COMMIT_GENERATION_UNKNOWN, notParseInGraph.getGeneration()); @@ -71,7 +55,6 @@ public void testParseHeaders() throws Exception { RevCommit parseInGraph = rw.lookupCommit(c1); parseInGraph.parseHeaders(rw); - assertTrue(parseInGraph instanceof RevCommitCG); assertNotNull(parseInGraph.getRawBuffer()); assertEquals(1, parseInGraph.getGeneration()); assertEquals(notParseInGraph.getId(), parseInGraph.getId()); @@ -84,7 +67,6 @@ public void testParseHeaders() throws Exception { RevCommit noBody = rw.lookupCommit(c1); noBody.parseHeaders(rw); - assertTrue(noBody instanceof RevCommitCG); assertNull(noBody.getRawBuffer()); assertEquals(1, noBody.getGeneration()); assertEquals(notParseInGraph.getId(), noBody.getId()); @@ -105,7 +87,6 @@ public void testParseCanonical() throws Exception { RevCommit parseInGraph = rw.lookupCommit(c1); parseInGraph.parseCanonical(rw, rw.getCachedBytes(c1)); - assertTrue(parseInGraph instanceof RevCommitCG); assertNotNull(parseInGraph.getRawBuffer()); assertEquals(1, parseInGraph.getGeneration()); assertEquals(notParseInGraph.getId(), parseInGraph.getId()); @@ -120,7 +101,6 @@ public void testParseCanonical() throws Exception { RevCommit noBody = rw.lookupCommit(c1); noBody.parseCanonical(rw, rw.getCachedBytes(c1)); - assertTrue(noBody instanceof RevCommitCG); assertNull(noBody.getRawBuffer()); assertEquals(1, noBody.getGeneration()); assertEquals(notParseInGraph.getId(), noBody.getId()); @@ -140,7 +120,6 @@ public void testInitializeShallowCommits() throws Exception { RevCommit parseInGraph = rw.lookupCommit(c1); parseInGraph.parseHeaders(rw); - assertTrue(parseInGraph instanceof RevCommitCG); assertNotNull(parseInGraph.getRawBuffer()); assertEquals(2, parseInGraph.getGeneration()); assertEquals(0, parseInGraph.getParentCount()); @@ -807,109 +786,4 @@ void testRevWalkBehavior(String branch, String compare) throws Exception { false, compare)); } - void assertCommitCntInGraph(int expect) { - assertEquals(expect, rw.commitGraph().getCommitCnt()); - } - - void assertCommits(List expect, List actual) { - assertEquals(expect.size(), actual.size()); - - for (int i = 0; i < expect.size(); i++) { - RevCommit c1 = expect.get(i); - RevCommit c2 = actual.get(i); - - assertEquals(c1.getId(), c2.getId()); - assertEquals(c1.getTree(), c2.getTree()); - assertEquals(c1.getCommitTime(), c2.getCommitTime()); - assertArrayEquals(c1.getParents(), c2.getParents()); - assertArrayEquals(c1.getRawBuffer(), c2.getRawBuffer()); - } - } - - Ref branch(RevCommit commit, String name) throws Exception { - return Git.wrap(db).branchCreate().setName(name) - .setStartPoint(commit.name()).call(); - } - - List travel(TreeFilter treeFilter, RevFilter revFilter, - RevSort revSort, boolean enableCommitGraph, String... starts) - throws Exception { - db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_COMMIT_GRAPH, enableCommitGraph); - - try (RevWalk walk = new RevWalk(db)) { - walk.setTreeFilter(treeFilter); - walk.setRevFilter(revFilter); - walk.sort(revSort); - walk.setRetainBody(false); - for (String start : starts) { - walk.markStart(walk.lookupCommit(db.resolve(start))); - } - List commits = new ArrayList<>(); - - if (enableCommitGraph) { - assertTrue(walk.commitGraph().getCommitCnt() > 0); - } else { - assertEquals(EMPTY, walk.commitGraph()); - } - - for (RevCommit commit : walk) { - commits.add(commit); - } - return commits; - } - } - - void enableAndWriteCommitGraph() throws Exception { - db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_COMMIT_GRAPH, true); - db.getConfig().setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, - ConfigConstants.CONFIG_KEY_WRITE_COMMIT_GRAPH, true); - db.getConfig().setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, - ConfigConstants.CONFIG_KEY_WRITE_CHANGED_PATHS, true); - GC gc = new GC(db); - gc.gc().get(); - } - - private void reinitializeRevWalk() { - rw.close(); - rw = new RevWalk(db); - } - - private static final class MockConfig extends FileBasedConfig { - private MockConfig() { - super(null, null); - } - - @Override - public void load() throws IOException, ConfigInvalidException { - // Do nothing - } - - @Override - public void save() throws IOException { - // Do nothing - } - - @Override - public boolean isOutdated() { - return false; - } - - @Override - public String toString() { - return "MockConfig"; - } - - @Override - public boolean getBoolean(final String section, final String name, - final boolean defaultValue) { - if (section.equals(ConfigConstants.CONFIG_COMMIT_GRAPH_SECTION) - && name.equals( - ConfigConstants.CONFIG_KEY_READ_CHANGED_PATHS)) { - return true; - } - return defaultValue; - } - } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java index d27d5c73fc4..744a063cf38 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java @@ -10,6 +10,7 @@ package org.eclipse.jgit.revwalk; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -364,4 +365,33 @@ public void testSort_TOPO_NON_INTERMIX_and_TOPO_throws() throws Exception { e.getMessage()); } } + + @Test + public void testSort_TOPO_reset_doesNotLeakFlags() throws Exception { + final RevCommit a = commit(); + final RevCommit b = commit(a); + final RevCommit c = commit(b); + final RevCommit d = commit(c); + + int appFlags = Integer.bitCount(RevWalk.APP_FLAGS); + + rw.sort(RevSort.TOPO); + markStart(d); + assertCommit(d, rw.next()); + assertCommit(c, rw.next()); + assertCommit(b, rw.next()); + assertCommit(a, rw.next()); + assertNull(rw.next()); + + + assertThat(Integer.bitCount(rw.freeFlags)) + .as("4 Flags should be allocated by TopoSortPendingGenerator") + .isEqualTo(appFlags - 4); + + rw.reset(); + + assertThat(Integer.bitCount(rw.freeFlags)) // + .as("Flags allocated by TopoSortPendingGenerator should be freed when calling RevWalk.reset()") + .isEqualTo(appFlags); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTopoWithCommitGraphTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTopoWithCommitGraphTest.java new file mode 100644 index 00000000000..5886f5fb557 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTopoWithCommitGraphTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2026, Vector Informatik GmbH + * + * 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.revwalk; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import org.assertj.core.api.ThrowingConsumer; +import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.treewalk.filter.ChangedPathTreeFilter; +import org.junit.Test; + +public class RevWalkSortTopoWithCommitGraphTest + extends AbstractRevWalkWithCommitGraphTest { + + @Test + public void testSort_TOPO_WithTreeFilter() throws Exception { + RevCommit a = commit(tree(file("a", blob("1")))); + RevCommit b = commit(tree(file("a", blob("2"))), a); + RevCommit c1 = commit(-5, tree(file("a", blob("3"))), b); + RevCommit c2 = commit(10, + tree(file("a", blob("2")), file("b", blob("1"))), b); + RevCommit d = commit(tree(file("a", blob("3")), file("b", blob("1"))), + c1, c2); + RevCommit e = commit(tree(file("a", blob("4")), file("b", blob("2"))), + d); + branch(e, "main"); + + testWalkBehavior( // + walk -> { + walk.sort(RevSort.TOPO); + walk.setTreeFilter(ChangedPathTreeFilter.create("a")); + walk.markStart(walk.lookupCommit(e)); + }, // + actual -> { + assertEquals(4, actual.size()); + + assertRewrittenCommit(actual.get(0), e, c1); + assertRewrittenCommit(actual.get(1), c1, b); + assertRewrittenCommit(actual.get(2), b, a); + assertRewrittenCommit(actual.get(3), a); + } // + ); + } + + @Test + public void testSort_TOPO_WithTreeFilter_Reachable() throws Exception { + RevCommit a = commit(tree(file("a", blob("1")))); + RevCommit b = commit(tree(file("a", blob("2"))), a); + RevCommit c1 = commit(-5, tree(file("a", blob("3"))), b); + RevCommit c2 = commit(10, + tree(file("a", blob("2")), file("b", blob("1"))), b); + RevCommit d = commit(tree(file("a", blob("3")), file("b", blob("1"))), + c1, c2); + RevCommit e = commit(tree(file("a", blob("4")), file("b", blob("2"))), + d); + branch(e, "main"); + + testWalkBehavior( // + walk -> { + walk.sort(RevSort.TOPO); + walk.setTreeFilter(ChangedPathTreeFilter.create("a")); + walk.markStart(walk.lookupCommit(e)); + walk.markUninteresting(walk.lookupCommit(b)); + }, // + actual -> { + assertEquals(2, actual.size()); + + assertRewrittenCommit(actual.get(0), e, c1); + assertRewrittenCommit(actual.get(1), c1, b); + } // + ); + } + + @Test + public void testSort_TOPO_WithTreeFilter_Reachable2() throws Exception { + RevCommit a = commit(tree(file("a", blob("1")))); + RevCommit b = commit(tree(file("a", blob("2"))), a); + RevCommit c1 = commit(-5, tree(file("a", blob("3"))), b); + RevCommit c2 = commit(10, + tree(file("a", blob("2")), file("b", blob("1"))), b); + RevCommit d = commit(tree(file("a", blob("3")), file("b", blob("1"))), + c1, c2); + RevCommit e = commit(tree(file("a", blob("4")), file("b", blob("2"))), + d); + branch(e, "main"); + + testWalkBehavior( // + walk -> { + walk.sort(RevSort.TOPO); + walk.setTreeFilter(ChangedPathTreeFilter.create("a")); + walk.markStart(walk.lookupCommit(e)); + walk.markUninteresting(walk.lookupCommit(e)); + }, // + actual -> { + assertEquals(0, actual.size()); + } // + ); + } + + // Test the RevWalk behavior with and without enabled commit graph + private void testWalkBehavior(ThrowingConsumer configureWalker, + Consumer> assertResult) throws Exception { + configureWalker.accept(rw); + List actual = new ArrayList<>(); + rw.forEach(actual::add); + + assertEquals(CommitGraph.EMPTY, rw.commitGraph()); + for (RevCommit c : actual) { + assertEquals(Constants.COMMIT_GENERATION_UNKNOWN, + c.getGeneration()); + } + + assertResult.accept(actual); + + enableAndWriteCommitGraph(); + reinitializeRevWalk(); + + configureWalker.accept(rw); + actual.clear(); + rw.forEach(actual::add); + + assertNotEquals(0, rw.commitGraph().getCommitCnt()); + for (RevCommit c : actual) { + assertNotEquals(Constants.COMMIT_GENERATION_UNKNOWN, + c.getGeneration()); + } + + assertResult.accept(actual); + } + + private void assertRewrittenCommit(RevCommit actual, AnyObjectId expectId, + RevCommit... expectParents) { + assertObjectId(actual, expectId); + assertEquals(expectParents.length, actual.getParentCount()); + + for (int i = 0; i < expectParents.length; i++) { + assertObjectId(actual.getParent(i), expectParents[i]); + } + } + + private void assertObjectId(AnyObjectId actual, AnyObjectId expectId) { + if (!AnyObjectId.isEqual(expectId, actual)) { + fail("Expected object id <%s>, got <%s>".formatted(expectId.name(), + actual.name())); + } + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java index 21fde3e76e7..2cdca73a758 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java @@ -14,6 +14,7 @@ import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K; import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; @@ -23,7 +24,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; +import org.eclipse.jgit.errors.TooLargePackException; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; @@ -50,6 +53,9 @@ public class PushConnectionTest { private ObjectId obj3; private String refName = "refs/tags/blob"; + private long maxPackSize = 0; // the maximum pack file size used by the + // server (0 means no limit) + @Before public void setUp() throws Exception { server = newRepo("server"); @@ -57,6 +63,9 @@ public void setUp() throws Exception { processedRefs = new ArrayList<>(); testProtocol = new TestProtocol<>(null, (Object req, Repository db) -> { ReceivePack rp = new ReceivePack(db); + if (maxPackSize > 0) { + rp.setMaxPackSizeLimit(maxPackSize); + } rp.setPreReceiveHook((ReceivePack receivePack, Collection cmds) -> { for (ReceiveCommand cmd : cmds) { @@ -169,6 +178,46 @@ public void limitCommandBytes() throws IOException { } } + @Test + public void limitPackSize() throws IOException { + // this maxPackSize leads to an unPackError + maxPackSize = 1; + + try (ObjectInserter ins = client.newObjectInserter()) { + // 1024 * 5 means five times the server side buffer size. We need data several + // times bigger the server side buffer size. This is necessary in order to cause + // the server buffer overflow when the client transmits data. This is necessary + // in order to enable the "JGit-Receive-Pack" thread to receive and begin + // processing data before the client is able to transfer all the data. When + // processing the first bytes of data, the server will detect that an error has + // occurred, write an error message and close the pipe. Then the client, when + // trying to write the remaining bytes, will receive a “Pipe closed” exception, + // which is what we need. The client must then check the error message from the + // server and throw an appropriate exception corresponding to that error message + // from the server. + byte[] arr = new byte[1024 * 5]; + new Random(1).nextBytes(arr); + obj2 = ins.insert(Constants.OBJ_BLOB, arr); + ins.flush(); + } + + Map updates = new HashMap<>(); + RemoteRefUpdate rru = new RemoteRefUpdate( + null, null, obj2, "refs/test/limitPackSize", + false, null, ObjectId.zeroId()); + updates.put(rru.getRemoteName(), rru); + + try (Transport tn = testProtocol.open(uri, client, "server"); + PushConnection connection = tn.openPush()) { + try { + connection.push(NullProgressMonitor.INSTANCE, updates); + fail("server did not abort"); + } catch (Exception e) { + assertTrue(e instanceof TooLargePackException); + } + } + } + @Test public void commandOrder() throws Exception { List updates = new ArrayList<>(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java index 595b970749e..bcc7082f780 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java @@ -42,22 +42,57 @@ package org.eclipse.jgit.transport; +import java.util.ArrayList; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; - -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.junit.TestRepository.BranchBuilder; +import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.transport.ReceiveCommand.Result; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.After; +import org.junit.Before; import org.junit.Test; /** Tests for receive-pack utilities. */ public class ReceivePackTest { + private URIish uri; + private TestProtocol testProtocol; + private InMemoryRepository client; + private InMemoryRepository server; + private TestRepository clientTestRepo; + private TestRepository serverTestRepo; + + @Before + public void setUp() throws Exception { + client = new InMemoryRepository(new DfsRepositoryDescription("client")); + server = new InMemoryRepository(new DfsRepositoryDescription("server")); + clientTestRepo = new TestRepository<>(client); + serverTestRepo = new TestRepository<>(server); + + testProtocol = new TestProtocol<>(null, (Object req, Repository db) -> { + ReceivePack rp = new ReceivePack(db); + return rp; + }); + uri = testProtocol.register(new Object(), server); + } + + @After + public void tearDown() { + Transport.unregister(testProtocol); + } + @Test public void parseCommand() throws Exception { String o = "0000000000000000000000000000000000000000"; @@ -81,6 +116,54 @@ public void parseCommand() throws Exception { assertParseCommandFails(o + " " + "X" + n.substring(1) + " " + r); } + /** + * Ensure receive-pack rejects a push to a one level ref (refs/master). + */ + @Test + public void rejectsCreationOfOneLevelRef() throws Exception { + // Create refs/master on the client so we can attempt to push it + RevCommit clientCommit; + BranchBuilder bb = clientTestRepo.branch("refs/master"); + clientCommit = bb.commit().noFiles().message("Testing").create(); + + ArrayList refUpdates = new ArrayList<>(); + refUpdates.add(new RemoteRefUpdate( + clientTestRepo.getRepository(), "refs/master", clientCommit, + "refs/master", false, /* force update */ + null, /* no local tracking ref */ + ObjectId.zeroId() // expected advertisement + )); + Transport tn = testProtocol.open(uri, client, "server"); + PushResult result = tn.push(NullProgressMonitor.INSTANCE, refUpdates); + RemoteRefUpdate update = result.getRemoteUpdate("refs/master"); + + assertEquals(RemoteRefUpdate.Status.REJECTED_OTHER_REASON, + update.getStatus()); + assertEquals(JGitText.get().funnyRefname, update.getMessage()); + } + + /** + * Allow deletion of one level refs (refs/master). + */ + @Test + public void acceptsDeletionOfOneLevelRef() throws Exception { + BranchBuilder bb = serverTestRepo.branch("refs/master"); + bb.update(bb.commit().noFiles().message("Testing").create()); + + ArrayList refUpdates = new ArrayList<>(); + refUpdates.add(new RemoteRefUpdate(null, null, ObjectId.zeroId(), + "refs/master", false, // force update + null, // no local tracking ref + null // expected advertisement + )); + Transport tn = testProtocol.open(uri, client, "server"); + PushResult result = tn.push(NullProgressMonitor.INSTANCE, refUpdates); + RemoteRefUpdate update = result.getRemoteUpdate("refs/master"); + + assertEquals(RemoteRefUpdate.Status.OK, update.getStatus()); + assertEquals(null, update.getMessage()); + } + private void assertParseCommandFails(String input) { try { ReceivePack.parseCommand(input); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java index 51e09e09a07..2a026763189 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java @@ -26,9 +26,14 @@ import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.pack.PackStatistics; import org.eclipse.jgit.transport.BasePackFetchConnection.FetchConfig; import org.eclipse.jgit.transport.resolver.ReceivePackFactory; @@ -112,6 +117,106 @@ public void testFetch() throws Exception { } } + @Test + public void fetchReportsLockFailureWhenAutoFollowTagIsCreated() + throws Exception { + String tagName = "foo"; + String tagRef = "refs/tags/" + tagName; + String remoteBranchName = "remotefoo"; + String forcedRemoteRef = "+refs/heads/" + remoteBranchName; + + RevCommit localCommit = local.commit().add("local.txt", "new").create(); + RevCommit remoteCommit = remote.branch(remoteBranchName).commit() + .add("remote.txt", "remote").create(); + RevTag remoteTag = remote.tag("foo", remoteCommit); + remote.update(tagRef, remoteTag); + + URIish uri = registerTestProtocolUpdatingRef((repo) -> repo.lightweightTag(tagName, localCommit)); + + + try (Git git = new Git(local.getRepository())) { + FetchResult result = git.fetch().setRemote(uri.toString()) + .setRefSpecs(new RefSpec(forcedRemoteRef + + ":refs/remotes/origin/" + remoteBranchName)) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(tagRef); + assertEquals(RefUpdate.Result.LOCK_FAILURE, update.getResult()); + // Tag hasn't been clobbered... + assertEquals(localCommit, + local.getRepository().exactRef(tagRef).getObjectId()); + // ...however the object has been downloaded + assertTrue(local.getRepository().getObjectDatabase() + .has(remoteCommit)); + } + } + + @Test + public void fetchReportsLockFailureWhenDestinationRefChanges() + throws Exception { + String localBranchName = "localfoo"; + String localRef = "refs/heads/" + localBranchName; + String remoteBranchName = "remotefoo"; + String forcedRemoteRef = "+refs/heads/" + remoteBranchName; + + RevCommit oldLocalCommit = local.branch(localBranchName).commit() + .add("local.txt", "old").create(); + RevCommit newLocalCommit = local.commit().parent(oldLocalCommit) + .add("local.txt", "new").create(); + RevCommit remoteCommit = remote.branch(remoteBranchName).commit() + .add("remote.txt", "remote").create(); + + URIish uri = registerTestProtocolUpdatingRef((repo) -> repo.update(localBranchName, newLocalCommit)); + + try (Git git = new Git(local.getRepository())) { + FetchResult result = git.fetch().setRemote(uri.toString()) + .setRefSpecs( + new RefSpec(forcedRemoteRef + ":" + localRef)) + .call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.LOCK_FAILURE, update.getResult()); + // Ref hasn't been clobbered... + assertEquals(newLocalCommit, + local.getRepository().exactRef(localRef).getObjectId()); + // ...however the object has been downloaded + assertTrue(local.getRepository().getObjectDatabase() + .has(remoteCommit)); + } + } + + @Test + public void fetchReportsLockFailureWhenDestinationRefIsCreated() + throws Exception { + String localBranchName = "localfoo"; + String localRef = "refs/heads/" + localBranchName; + String remoteBranchName = "remotefoo"; + String forcedRemoteRef = "+refs/heads/" + remoteBranchName; + + RevCommit newLocalCommit = local.commit().add("local.txt", "new") + .create(); + RevCommit remoteCommit = remote.branch(remoteBranchName).commit() + .add("remote.txt", "remote").create(); + + URIish uri = registerTestProtocolUpdatingRef((repo) -> repo.update(localBranchName, newLocalCommit)); + + try (Git git = new Git(local.getRepository())) { + FetchResult result = git.fetch().setRemote(uri.toString()) + .setRefSpecs( + new RefSpec(forcedRemoteRef + ":" + localRef)) + .call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.LOCK_FAILURE, update.getResult()); + // Ref hasn't been clobbered... + assertEquals(newLocalCommit, + local.getRepository().exactRef(localRef).getObjectId()); + // ...however the object has been downloaded + assertTrue(local.getRepository().getObjectDatabase() + .has(remoteCommit)); + } + } + @Test public void testPush() throws Exception { ObjectId master = local.branch("master").commit().create(); @@ -258,6 +363,188 @@ public void testReceivePackFactory() throws Exception { } } + @Test + public void nonForcedFetchRejectedWithConcurrentLocalRefUpdate() + throws Exception { + String localRef = Constants.R_HEADS + "localfoo"; + String remoteBranchName = "remotefoo"; + String nonForcedRemoteRef = Constants.R_HEADS + remoteBranchName; + + try (Repository repository = local.getRepository(); + Git git = new Git(repository); + RevWalk revWalk = local.getRevWalk()) { + RefSpec nonForcedFetchRefSpec = new RefSpec( + nonForcedRemoteRef + ":" + localRef); + RevCommit oldLocalCommit = remote.branch(remoteBranchName) + .commit().add("base.txt", "base").create(); + + git.fetch().setRemote(registerDefaultTestProtocol().toString()).setRefSpecs(nonForcedFetchRefSpec) + .call(); + assertEquals(oldLocalCommit, repository.exactRef(localRef).getObjectId()); + + RevCommit updatedLocalCommit = local.commit() + .parent(revWalk.parseCommit(oldLocalCommit)) + .add("local.txt", "new").create(); + RevCommit remoteCommit = remote.commit().parent(oldLocalCommit) + .add("remote.txt", "remote").create(); + remote.update(remoteBranchName, remoteCommit); + + URIish uri = registerTestProtocolUpdatingRef((repo) -> repo.update(localRef, updatedLocalCommit)); + FetchResult result = git.fetch().setRemote(uri.toString()) + .setRefSpecs(nonForcedFetchRefSpec).call(); + + // Fetch has been rejected (non-ff) + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.REJECTED, update.getResult()); + + // Fetched object has been downloaded + assertTrue(repository.getObjectDatabase() + .has(remoteCommit)); + // ... but the local ref has not been altered + assertEquals(updatedLocalCommit, + repository.exactRef(localRef).getObjectId()); + } + } + + @Test + public void forcedFetchReportsLockFailureWhenDestinationRefIsDeleted() + throws Exception { + String localBranchName = "localfoo"; + String localRef = Constants.R_HEADS + localBranchName; + String remoteBranchName = "remotefoo"; + String forcedRemoteRef = "+" + Constants.R_HEADS + remoteBranchName; + + local.branch(localBranchName).commit() + .add("local.txt", "old").create(); + RevCommit remoteCommit = remote.branch(remoteBranchName).commit() + .add("remote.txt", "remote").create(); + + URIish uri = registerTestProtocolUpdatingRef((repo) -> { + RefUpdate refUpdate = repo.getRepository().updateRef(localRef); + refUpdate.setForceUpdate(true); + refUpdate.delete(); + }); + + try (Git git = new Git(local.getRepository())) { + FetchResult result = git.fetch() + .setRemote(uri.toString()) + .setRefSpecs(new RefSpec(forcedRemoteRef + ":" + localRef)) + .call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.LOCK_FAILURE, update.getResult()); + assertNull(local.getRepository().exactRef(localRef)); + assertTrue(local.getRepository().getObjectDatabase() + .has(remoteCommit)); + } + } + + @Test + public void forcedFetchReportsLockFailureWhenDestinationRefAlreadyHasNewId() + throws Exception { + String localBranchName = "localfoo"; + String localRef = Constants.R_HEADS + localBranchName; + String remoteBranchName = "remotefoo"; + String forcedRemoteRef = "+" + Constants.R_HEADS + remoteBranchName; + String tmpRef = Constants.R_HEADS + "tmp"; + + RevCommit oldLocalCommit = local.branch(localBranchName).commit() + .add("local.txt", "old").create(); + RevCommit remoteCommit = remote.branch(remoteBranchName).commit() + .add("remote.txt", "remote").create(); + + try (Git git = new Git(local.getRepository())) { + // Pre-fetch the remote object into the local object database so the + // simulated concurrent local update can point at it. + git.fetch().setRemote(registerDefaultTestProtocol().toString()) + .setRefSpecs(new RefSpec(forcedRemoteRef + ":" + tmpRef)) + .call(); + + local.update(localRef, oldLocalCommit); + + URIish uri = registerTestProtocolUpdatingRef( + (repo) -> repo.update(localRef, remoteCommit)); + + FetchResult result = git.fetch().setRemote(uri.toString()) + .setRefSpecs(new RefSpec(forcedRemoteRef + ":" + localRef)) + .call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.LOCK_FAILURE, update.getResult()); + assertEquals(remoteCommit, + local.getRepository().exactRef(localRef).getObjectId()); + } + } + + @Test + public void nonForcedFetchReportsLockFailureWhenConcurrentUpdateIsFastForward() + throws Exception { + String localBranchName = "localfoo"; + String localRef = Constants.R_HEADS + localBranchName; + String remoteBranchName = "remotefoo"; + String nonForcedRemoteRef = Constants.R_HEADS + remoteBranchName; + String tmpRef = "refs/heads/tmp"; + + RevCommit baseCommit = remote.branch(remoteBranchName).commit() + .add("base.txt", "base").create(); + RevCommit updatedLocalCommit = remote.commit().parent(baseCommit) + .add("local.txt", "local").create(); + RevCommit remoteCommit = remote.commit().parent(updatedLocalCommit) + .add("remote.txt", "remote").create(); + remote.update(remoteBranchName, remoteCommit); + + try (Git git = new Git(local.getRepository())) { + git.fetch().setRemote(registerDefaultTestProtocol().toString()) + .setRefSpecs(new RefSpec(nonForcedRemoteRef + ":" + tmpRef)) + .call(); + + local.update(localRef, baseCommit); + + URIish uri = registerTestProtocolUpdatingRef( + (repo) -> repo.update(localRef, updatedLocalCommit)); + + FetchResult result = git.fetch().setRemote(uri.toString()) + .setRefSpecs(new RefSpec(nonForcedRemoteRef + ":" + localRef)) + .call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.LOCK_FAILURE, update.getResult()); + assertEquals(updatedLocalCommit, + local.getRepository().exactRef(localRef).getObjectId()); + assertTrue(local.getRepository().getObjectDatabase() + .has(remoteCommit)); + } + } + + @Test + public void nonForcedFetchRejectedWhenCurrentRefUnchangedButNonFastForward() + throws Exception { + String localBranchName = "localfoo"; + String localRef = Constants.R_HEADS + localBranchName; + String remoteBranchName = "remotefoo"; + String nonForcedRemoteRef = Constants.R_HEADS + remoteBranchName; + + RevCommit localCommit = local.branch(localBranchName).commit() + .add("local.txt", "local").create(); + RevCommit remoteCommit = remote.branch(remoteBranchName).commit() + .add("remote.txt", "remote").create(); + + try (Git git = new Git(local.getRepository())) { + FetchResult result = git.fetch() + .setRemote(registerDefaultTestProtocol().toString()) + .setRefSpecs( + new RefSpec(nonForcedRemoteRef + ":" + localRef)) + .call(); + + TrackingRefUpdate update = result.getTrackingRefUpdate(localRef); + assertEquals(RefUpdate.Result.REJECTED, update.getResult()); + assertEquals(localCommit, + local.getRepository().exactRef(localRef).getObjectId()); + assertTrue(local.getRepository().getObjectDatabase() + .has(remoteCommit)); + } + } + private TestProtocol registerDefault() { return registerProto(new DefaultUpload(), new DefaultReceive()); } @@ -269,4 +556,26 @@ private TestProtocol registerProto(UploadPackFactory upf, Transport.register(proto); return proto; } + + @FunctionalInterface + interface TestRepositoryUpdateFunc { + void call(TestRepository repository) throws Exception; + } + + private URIish registerTestProtocolUpdatingRef(TestRepositoryUpdateFunc repositoryUpdateFunc) { + TestProtocol proto = registerProto((User req, Repository db) -> { + try { + repositoryUpdateFunc.call(local); + } catch (Exception e) { + throw new AssertionError("Cannot update local ref", e); + } + return new UploadPack(db); + }, new DefaultReceive()); + return proto.register(new User("user"), remote.getRepository()); + } + + private URIish registerDefaultTestProtocol() { + TestProtocol setupProto = registerDefault(); + return setupProto.register(new User("user"), remote.getRepository()); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java index 0513da2d155..f7dab121e8b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FilterCommandsTest.java @@ -16,8 +16,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; import java.util.HashSet; +import java.util.Random; import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.MergeResult; @@ -70,6 +73,33 @@ public int run() throws IOException { } } + private static class NoOpCommandFactory implements FilterCommandFactory { + + @Override + public FilterCommand create(Repository db, InputStream in, + OutputStream out) throws IOException { + return new FilterCommand(in, out) { + + private byte[] buf = new byte[32 * 1024]; + + @Override + public int run() throws IOException { + int n = in.read(buf); + if (n < 0) { + in.close(); + out.close(); + return -1; + } + if (n > 0) { + out.write(buf, 0, n); + } + return n; + } + + }; + } + } + @Override @Before public void setUp() throws Exception { @@ -148,6 +178,46 @@ public void testBuiltinCleanFilter() throws Exception { indexState(CONTENT)); } + @Test + public void testCleanLargeFile() throws Exception { + String builtinCommandName = "jgit://builtin/test/clean"; + FilterCommandRegistry.register(builtinCommandName, + new NoOpCommandFactory()); + StoredConfig config = git.getRepository().getConfig(); + config.setString("filter", "test", "clean", builtinCommandName); + config.save(); + + writeTrashFile(".gitattributes", "*.bin filter=test"); + git.add().addFilepattern(".gitattributes").call(); + git.commit().setMessage("add filter").call(); + + File f = new File(git.getRepository().getWorkTree(), "a.bin"); + long length = 0; + try (OutputStream out = Files.newOutputStream(f.toPath())) { + byte[] buf = new byte[8 * 1024]; + Random r = ThreadLocalRandom.current(); + while (length < TemporaryBuffer.DEFAULT_IN_CORE_LIMIT) { + r.nextBytes(buf); + buf[0] = 0; + out.write(buf); + length += buf.length; + } + // Write a few bytes extra, just so that we don't have a + // multiple of 8k, and we're beyond the in-memory limit. + r.nextBytes(buf); + out.write(buf, 0, 19); + length += 19; + } + + fsTick(f); + git.add().addFilepattern("a.bin").call(); + assertEquals( + "[.gitattributes, mode:100644, length:17]" + + "[Test.txt, mode:100644, length:11]" + + "[a.bin, mode:100644, length:" + length + "]", + indexState(LENGTH)); + } + @Test public void testBuiltinSmudgeFilter() throws IOException, GitAPIException { String builtinCommandName = "jgit://builtin/test/smudge"; diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF index b3ecf33ca23..e376952db1c 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF @@ -4,15 +4,15 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ui Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Export-Package: org.eclipse.jgit.awtui;version="7.6.0" -Import-Package: org.eclipse.jgit.errors;version="[7.6.0,7.7.0)", - org.eclipse.jgit.lib;version="[7.6.0,7.7.0)", - org.eclipse.jgit.nls;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revplot;version="[7.6.0,7.7.0)", - org.eclipse.jgit.revwalk;version="[7.6.0,7.7.0)", - org.eclipse.jgit.transport;version="[7.6.0,7.7.0)", - org.eclipse.jgit.util;version="[7.6.0,7.7.0)" +Export-Package: org.eclipse.jgit.awtui;version="7.8.0" +Import-Package: org.eclipse.jgit.errors;version="[7.8.0,7.9.0)", + org.eclipse.jgit.lib;version="[7.8.0,7.9.0)", + org.eclipse.jgit.nls;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revplot;version="[7.8.0,7.9.0)", + org.eclipse.jgit.revwalk;version="[7.8.0,7.9.0)", + org.eclipse.jgit.transport;version="[7.8.0,7.9.0)", + org.eclipse.jgit.util;version="[7.8.0,7.9.0)" diff --git a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF index e20c4f219c8..54a8d561d1e 100644 --- a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ 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.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit.ui;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit.ui;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index 2acf0e0b343..40056db33ca 100644 --- a/org.eclipse.jgit.ui/pom.xml +++ b/org.eclipse.jgit.ui/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit.ui diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 6a7d44a7f4c..641eb50b3ef 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -8,6 +8,20 @@ + + + + + + + + + + + + + + diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD index 1e9b7708a0f..5d4bce4207a 100644 --- a/org.eclipse.jgit/BUILD +++ b/org.eclipse.jgit/BUILD @@ -16,6 +16,12 @@ RESOURCES = glob(["resources/**"]) java_library( name = "jgit_non_stamped", srcs = SRCS, + javacopts = [ + "-Xep:ReferenceEquality:OFF", + "-Xep:StringEquality:OFF", + "-Xep:TypeParameterUnusedInFormals:OFF", + "-Xep:DefaultCharset:OFF", + ], resource_strip_prefix = "org.eclipse.jgit/resources", resources = RESOURCES, deps = [ @@ -24,12 +30,6 @@ java_library( "//lib:javaewah", "//lib:slf4j-api", ], - javacopts = [ - "-Xep:ReferenceEquality:OFF", - "-Xep:StringEquality:OFF", - "-Xep:TypeParameterUnusedInFormals:OFF", - "-Xep:DefaultCharset:OFF", - ] ) genrule( diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 15ae6efaadf..8e92528f808 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-Localization: OSGI-INF/l10n/plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy @@ -11,8 +11,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git Service-Component: OSGI-INF/org.eclipse.jgit.internal.util.CleanupService.xml Eclipse-ExtensibleAPI: true -Export-Package: org.eclipse.jgit.annotations;version="7.6.0", - org.eclipse.jgit.api;version="7.6.0"; +Export-Package: org.eclipse.jgit.annotations;version="7.8.0", + org.eclipse.jgit.api;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.notes, org.eclipse.jgit.dircache, @@ -27,21 +27,21 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.revwalk.filter, org.eclipse.jgit.blame, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="7.6.0"; + org.eclipse.jgit.api.errors;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.errors", - org.eclipse.jgit.attributes;version="7.6.0"; + org.eclipse.jgit.attributes;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk", - org.eclipse.jgit.blame;version="7.6.0"; + org.eclipse.jgit.blame;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.blame.cache, org.eclipse.jgit.diff, org.eclipse.jgit.treewalk.filter", - org.eclipse.jgit.blame.cache;version="7.6.0"; + org.eclipse.jgit.blame.cache;version="7.8.0"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.diff;version="7.6.0"; + org.eclipse.jgit.diff;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.patch, @@ -49,55 +49,55 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk, org.eclipse.jgit.util", - org.eclipse.jgit.dircache;version="7.6.0"; + org.eclipse.jgit.dircache;version="7.8.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.6.0"; + org.eclipse.jgit.errors;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.dircache, org.eclipse.jgit.lib", - org.eclipse.jgit.events;version="7.6.0"; + org.eclipse.jgit.events;version="7.8.0"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.fnmatch;version="7.6.0", - org.eclipse.jgit.gitrepo;version="7.6.0"; + org.eclipse.jgit.fnmatch;version="7.8.0", + org.eclipse.jgit.gitrepo;version="7.8.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.6.0";x-internal:=true, - org.eclipse.jgit.hooks;version="7.6.0"; + org.eclipse.jgit.gitrepo.internal;version="7.8.0";x-internal:=true, + org.eclipse.jgit.hooks;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.ignore;version="7.6.0", - org.eclipse.jgit.ignore.internal;version="7.6.0"; + org.eclipse.jgit.ignore;version="7.8.0", + org.eclipse.jgit.ignore.internal;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal;version="7.6.0"; + org.eclipse.jgit.internal;version="7.8.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.diff;version="7.6.0"; + org.eclipse.jgit.internal.diff;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.diffmergetool;version="7.6.0"; + org.eclipse.jgit.internal.diffmergetool;version="7.8.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.6.0"; + org.eclipse.jgit.internal.fsck;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.revwalk;version="7.6.0"; + org.eclipse.jgit.internal.revwalk;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.commitgraph;version="7.6.0"; + org.eclipse.jgit.internal.storage.commitgraph;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.dfs;version="7.6.0"; + org.eclipse.jgit.internal.storage.dfs;version="7.8.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.6.0"; + org.eclipse.jgit.internal.storage.file;version="7.8.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, org.eclipse.jgit.junit.http, @@ -109,39 +109,39 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.ssh.apache, org.eclipse.jgit.ssh.apache.test, org.eclipse.jgit.ssh.jsch.test", - org.eclipse.jgit.internal.storage.io;version="7.6.0"; + org.eclipse.jgit.internal.storage.io;version="7.8.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.memory;version="7.6.0"; + org.eclipse.jgit.internal.storage.memory;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.midx;version="7.6.0"; + org.eclipse.jgit.internal.storage.midx;version="7.8.0"; x-friends:="org.eclipse.jgit.pgm, org.eclipse.jgit.test", - org.eclipse.jgit.internal.storage.pack;version="7.6.0"; + org.eclipse.jgit.internal.storage.pack;version="7.8.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.reftable;version="7.6.0"; + org.eclipse.jgit.internal.storage.reftable;version="7.8.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.6.0";x-internal:=true, - org.eclipse.jgit.internal.transport.connectivity;version="7.6.0"; + org.eclipse.jgit.internal.submodule;version="7.8.0";x-internal:=true, + org.eclipse.jgit.internal.transport.connectivity;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.http;version="7.6.0"; + org.eclipse.jgit.internal.transport.http;version="7.8.0"; x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.parser;version="7.6.0"; + org.eclipse.jgit.internal.transport.parser;version="7.8.0"; x-friends:="org.eclipse.jgit.http.server, org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.ssh;version="7.6.0"; + org.eclipse.jgit.internal.transport.ssh;version="7.8.0"; x-friends:="org.eclipse.jgit.ssh.apache, org.eclipse.jgit.ssh.jsch, org.eclipse.jgit.test", - org.eclipse.jgit.internal.util;version="7.6.0"; + org.eclipse.jgit.internal.util;version="7.8.0"; x-friends:="org.eclipse.jgit.junit", - org.eclipse.jgit.lib;version="7.6.0"; + org.eclipse.jgit.lib;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util.sha1, org.eclipse.jgit.dircache, @@ -156,12 +156,12 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.util, org.eclipse.jgit.submodule, org.eclipse.jgit.util.time", - org.eclipse.jgit.lib.internal;version="7.6.0"; + org.eclipse.jgit.lib.internal;version="7.8.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.pgm, org.eclipse.egit.ui", - org.eclipse.jgit.logging;version="7.6.0", - org.eclipse.jgit.merge;version="7.6.0"; + org.eclipse.jgit.logging;version="7.8.0", + org.eclipse.jgit.merge;version="7.8.0"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -170,42 +170,42 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.util, org.eclipse.jgit.api, org.eclipse.jgit.attributes", - org.eclipse.jgit.nls;version="7.6.0", - org.eclipse.jgit.notes;version="7.6.0"; + org.eclipse.jgit.nls;version="7.8.0", + org.eclipse.jgit.notes;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="7.6.0"; + org.eclipse.jgit.patch;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="7.6.0"; + org.eclipse.jgit.revplot;version="7.8.0"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.lib", - org.eclipse.jgit.revwalk;version="7.6.0"; + org.eclipse.jgit.revwalk;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk, org.eclipse.jgit.internal.storage.commitgraph", - org.eclipse.jgit.revwalk.filter;version="7.6.0"; + org.eclipse.jgit.revwalk.filter;version="7.8.0"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="7.6.0"; + org.eclipse.jgit.storage.file;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="7.6.0"; + org.eclipse.jgit.storage.pack;version="7.8.0"; uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="7.6.0"; + org.eclipse.jgit.submodule;version="7.8.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.treewalk, org.eclipse.jgit.util", - org.eclipse.jgit.transport;version="7.6.0"; + org.eclipse.jgit.transport;version="7.8.0"; uses:="javax.crypto, org.eclipse.jgit.hooks, org.eclipse.jgit.util.io, @@ -218,21 +218,21 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.transport.resolver, org.eclipse.jgit.storage.pack, org.eclipse.jgit.errors", - org.eclipse.jgit.transport.http;version="7.6.0"; + org.eclipse.jgit.transport.http;version="7.8.0"; uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="7.6.0"; + org.eclipse.jgit.transport.resolver;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.lib", - org.eclipse.jgit.treewalk;version="7.6.0"; + org.eclipse.jgit.treewalk;version="7.8.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.6.0"; + org.eclipse.jgit.treewalk.filter;version="7.8.0"; uses:="org.eclipse.jgit.treewalk", - org.eclipse.jgit.util;version="7.6.0"; + org.eclipse.jgit.util;version="7.8.0"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.hooks, org.eclipse.jgit.revwalk, @@ -245,12 +245,12 @@ Export-Package: org.eclipse.jgit.annotations;version="7.6.0", org.eclipse.jgit.treewalk, javax.net.ssl, org.eclipse.jgit.util.time", - org.eclipse.jgit.util.io;version="7.6.0"; + org.eclipse.jgit.util.io;version="7.8.0"; uses:="org.eclipse.jgit.attributes, org.eclipse.jgit.lib, org.eclipse.jgit.treewalk", - org.eclipse.jgit.util.sha1;version="7.6.0", - org.eclipse.jgit.util.time;version="7.6.0" + org.eclipse.jgit.util.sha1;version="7.8.0", + org.eclipse.jgit.util.time;version="7.8.0" Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", javax.crypto, javax.management, diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index 48db010fc9e..09b1ed35b42 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF @@ -3,6 +3,6 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 7.6.0.qualifier +Bundle-Version: 7.8.0.qualifier Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Eclipse-SourceBundle: org.eclipse.jgit;version="7.6.0.qualifier";roots="." +Eclipse-SourceBundle: org.eclipse.jgit;version="7.8.0.qualifier";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 890cb9cbf19..d893037f5dc 100644 --- a/org.eclipse.jgit/pom.xml +++ b/org.eclipse.jgit/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jgit org.eclipse.jgit-parent - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT org.eclipse.jgit 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 8889d7562c9..4b6d0865217 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -117,6 +117,7 @@ cannotMkdirObjectPath=Cannot create directory {0}/{1}: {2} cannotMoveIndexTo=Cannot move index to {0} cannotMovePackTo=Cannot move pack to {0} cannotOpenService=cannot open {0} +cannotOpenMidx=Cannot open midx at {0}: {1} cannotParseDate=The date specification "{0}" could not be parsed with the following formats: {1} cannotParseGitURIish=Cannot parse Git URI-ish cannotPullOnARepoWithState=Cannot pull into a repository with state: {0} @@ -260,6 +261,7 @@ deepenNotWithDeepen=Cannot combine deepen with deepen-not deepenSinceWithDeepen=Cannot combine deepen with deepen-since deleteBranchUnexpectedResult=Delete branch returned unexpected result {0} deleteFileFailed=Could not delete file {0} +deleteLooseRef=Deleted loose ref {}, object Id {} deletedOrphanInPackDir=Deleted orphaned file {} deleteRequiresZeroNewId=Delete requires new ID to be zero deleteTagUnexpectedResult=Delete tag returned unexpected result {0} @@ -512,6 +514,7 @@ 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 +midxChunkTooBig=chunk 0x{0} is too big (%d bytes) midxChunkUnknown=unknown midx chunk: 0x{0} minutesAgo={0} minutes ago mismatchOffset=mismatch offset for object {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 b4d1cab5139..23bda6f1846 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java @@ -20,7 +20,9 @@ import java.text.MessageFormat; import java.time.Instant; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Objects; import org.eclipse.jgit.api.errors.FilterFailedException; import org.eclipse.jgit.api.errors.GitAPIException; @@ -113,6 +115,36 @@ public AddCommand addFilepattern(String filepattern) { return this; } + /** + * Add paths to a file/directory whose content should be added. + * + * @param patterns + * repository-relative paths of file/directory to add (with + * / as separator) + * @return {@code this} + * @since 7.6 + */ + public AddCommand addFilepatterns(String... patterns) { + List.of(Objects.requireNonNull(patterns)).forEach(this::addFilepattern); + return this; + } + + /** + * Add paths to a file/directory whose content should be added. + * + * @param patterns + * repository-relative paths of file/directory to add (with + * / as separator) + * @return {@code this} + * @since 7.6 + */ + public AddCommand addFilepatterns(Collection patterns) { + if (patterns != null) { + patterns.forEach(this::addFilepattern); + } + return this; + } + /** * Allow clients to provide their own implementation of a FileTreeIterator * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java index a353d1a1358..6761f1eee56 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java @@ -10,6 +10,9 @@ package org.eclipse.jgit.api; import static org.eclipse.jgit.api.CherryPickCommitMessageProvider.ORIGINAL; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import java.io.IOException; @@ -18,6 +21,7 @@ import java.util.List; import java.util.Map; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; @@ -73,6 +77,8 @@ public class CherryPickCommand extends GitCommand { private ContentMergeStrategy contentStrategy; + private ConflictStyle conflictStyle; + private Integer mainlineParentNumber; private boolean noCommit = false; @@ -138,9 +144,9 @@ public CherryPickResult call() throws GitAPIException, NoMessageException, boolean noProblems; Map failingPaths = null; List unmergedPaths = null; - if (merger instanceof ResolveMerger) { - ResolveMerger resolveMerger = (ResolveMerger) merger; + if (merger instanceof ResolveMerger resolveMerger) { resolveMerger.setContentMergeStrategy(contentStrategy); + resolveMerger.setConflictStyle(getConflictStyle()); resolveMerger.setCommitNames( new String[] { "BASE", ourName, cherryPickName }); //$NON-NLS-1$ resolveMerger @@ -362,6 +368,25 @@ public CherryPickCommand setContentMergeStrategy( return this; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @return {@code this} + * @since 7.6 + */ + public CherryPickCommand setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + return this; + } + + private ConflictStyle getConflictStyle() { + return conflictStyle != null ? conflictStyle + : repo.getConfig().getEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + /** * Set the (1-based) parent number to diff against * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java index 7064f5a57a9..a79fbf73497 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java @@ -75,6 +75,8 @@ public class MergeCommand extends GitCommand { private ContentMergeStrategy contentStrategy; + private ConflictStyle conflictStyle; + private List commits = new ArrayList<>(); private Boolean squash; @@ -336,9 +338,9 @@ public MergeResult call() throws GitAPIException, NoHeadException, Map> lowLevelResults = null; Map failingPaths = null; List unmergedPaths = null; - if (merger instanceof ResolveMerger) { - ResolveMerger resolveMerger = (ResolveMerger) merger; + if (merger instanceof ResolveMerger resolveMerger) { resolveMerger.setContentMergeStrategy(contentStrategy); + resolveMerger.setConflictStyle(conflictStyle); resolveMerger.setCommitNames(new String[] { "BASE", "HEAD", ref.getName() }); //$NON-NLS-1$ //$NON-NLS-2$ resolveMerger.setWorkingTreeIterator(new FileTreeIterator(repo)); @@ -456,6 +458,8 @@ private void fallBackToConfiguration() { commit = Boolean.valueOf(config.isCommit()); if (fastForwardMode == null) fastForwardMode = config.getFastForwardMode(); + if (conflictStyle == null) + conflictStyle = config.getConflictStyle(); } private void updateHead(StringBuilder refLogMessage, ObjectId newHeadId, @@ -510,6 +514,19 @@ public MergeCommand setContentMergeStrategy(ContentMergeStrategy strategy) { return this; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @return {@code this} + * @since 7.6 + */ + public MergeCommand setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + return this; + } + /** * Reference to a commit to be merged with the current head * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java index 1ff6e98b12a..83c063b2ffa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/NameRevCommand.java @@ -51,8 +51,8 @@ private static class NameRevCommit extends RevCommit { private int distance; private long cost; - private NameRevCommit(AnyObjectId id) { - super(id); + private NameRevCommit(AnyObjectId id, int graphPosition) { + super(id, graphPosition); } private StringBuilder format() { @@ -96,8 +96,8 @@ protected NameRevCommand(Repository repo) { revs = new ArrayList<>(2); walk = new RevWalk(repo) { @Override - public NameRevCommit createCommit(AnyObjectId id) { - return new NameRevCommit(id); + protected RevCommit createCommit(AnyObjectId id, int graphPos) { + return new NameRevCommit(id, graphPos); } }; } 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 4b2cee45c26..ff5dbffea22 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java @@ -11,10 +11,15 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; + import java.io.IOException; import java.text.MessageFormat; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.api.MergeCommand.FastForwardMode.Merge; import org.eclipse.jgit.api.RebaseCommand.Operation; @@ -72,6 +77,8 @@ public class PullCommand extends TransportCommand { private ContentMergeStrategy contentStrategy; + private ConflictStyle conflictStyle; + private TagOpt tagOption; private FastForwardMode fastForwardMode; @@ -361,6 +368,7 @@ public PullResult call() throws GitAPIException, .setOperation(Operation.BEGIN) .setStrategy(strategy) .setContentMergeStrategy(contentStrategy) + .setConflictStyle(getConflictStyle()) .setPreserveMerges( pullRebaseMode == BranchRebaseMode.MERGES) .call(); @@ -371,6 +379,7 @@ public PullResult call() throws GitAPIException, .setProgressMonitor(monitor) .setStrategy(strategy) .setContentMergeStrategy(contentStrategy) + .setConflictStyle(getConflictStyle()) .setFastForward(getFastForwardMode()).call(); monitor.update(1); result = new PullResult(fetchRes, remote, mergeRes); @@ -463,6 +472,25 @@ public PullCommand setContentMergeStrategy(ContentMergeStrategy strategy) { return this; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @return {@code this} + * @since 7.6 + */ + public PullCommand setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + return this; + } + + private ConflictStyle getConflictStyle() { + return conflictStyle != null ? conflictStyle + : repo.getConfig().getEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + /** * Set the specification of annotated tag behavior during fetch * 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 3ae7a6c81e2..ba8461d759f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -11,6 +11,9 @@ package org.eclipse.jgit.api; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import java.io.ByteArrayOutputStream; import java.io.File; @@ -31,6 +34,7 @@ import java.util.regex.Pattern; import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.RebaseResult.Status; import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.errors.CheckoutConflictException; @@ -220,6 +224,8 @@ public enum Operation { private ContentMergeStrategy contentStrategy; + private ConflictStyle conflictStyle; + private boolean preserveMerges = false; /** @@ -557,6 +563,7 @@ private RebaseResult cherryPickCommitFlattening(RevCommit commitToPick) .setReflogPrefix(REFLOG_PREFIX) .setStrategy(strategy) .setContentMergeStrategy(contentStrategy) + .setConflictStyle(getConflictStyle()) .call(); switch (cherryPickResult.getStatus()) { case FAILED: @@ -611,7 +618,8 @@ private RebaseResult cherryPickCommitPreservingMerges(RevCommit commitToPick) .setOurCommitName(ourCommitName) .setReflogPrefix(REFLOG_PREFIX) .setStrategy(strategy) - .setContentMergeStrategy(contentStrategy); + .setContentMergeStrategy(contentStrategy) + .setConflictStyle(getConflictStyle()); if (isMerge) { pickCommand.setMainlineParentNumber(1); // We write a MERGE_HEAD and later commit explicitly @@ -649,6 +657,7 @@ private RebaseResult cherryPickCommitPreservingMerges(RevCommit commitToPick) .setProgressMonitor(monitor) .setStrategy(strategy) .setContentMergeStrategy(contentStrategy) + .setConflictStyle(getConflictStyle()) .setCommit(false); for (int i = 1; i < commitToPick.getParentCount(); i++) merge.include(newParents.get(i)); @@ -1039,6 +1048,8 @@ private RevCommit continueRebase() throws GitAPIException, IOException { CommitCommand commit = git.commit(); commit.setMessage(rebaseState.readFile(MESSAGE)); commit.setAuthor(parseAuthor()); + commit.setCleanupMode( + commitConfig.resolve(CleanupMode.DEFAULT, false)); return commit.call(); } } @@ -1697,6 +1708,25 @@ public RebaseCommand setContentMergeStrategy(ContentMergeStrategy strategy) { return this; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @return {@code this} + * @since 7.6 + */ + public RebaseCommand setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + return this; + } + + private ConflictStyle getConflictStyle() { + return conflictStyle != null ? conflictStyle + : repo.getConfig().getEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + /** * Whether to preserve merges during rebase * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java index 2aa64df46fb..370fae86780 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java @@ -9,6 +9,7 @@ */ package org.eclipse.jgit.api; +import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -303,4 +304,33 @@ public List getUncommittedChanges() { return uncommittedChanges; } + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder sb = new StringBuilder("RebaseResult["); + sb.append(status); + switch (status) { + case CONFLICTS: + sb.append(" Conflicts: "); + sb.append(conflicts.size()); + break; + case STOPPED: + sb.append(" At commit : "); + sb.append(currentCommit); + break; + case FAILED: + sb.append(" Failed Paths : "); + sb.append(failingPaths.size()); + sb.append(", reasons "); + sb.append(EnumSet.copyOf(failingPaths.values())); + break; + case UNCOMMITTED_CHANGES: + sb.append(" Uncommitted Changes :"); + sb.append(uncommittedChanges.size()); + break; + default: + } + sb.append("]"); + return sb.toString(); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java index 6643c836627..5a107d57ad0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java @@ -9,6 +9,9 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; import java.io.IOException; @@ -17,6 +20,7 @@ import java.util.List; import java.util.Map; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.api.errors.GitAPIException; @@ -74,6 +78,8 @@ public class RevertCommand extends GitCommand { private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; + private ConflictStyle conflictStyle; + /** *

* Constructor for RevertCommand. @@ -138,6 +144,7 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException, + srcCommit.getShortMessage(); ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo); + merger.setConflictStyle(getConflictStyle()); merger.setWorkingTreeIterator(new FileTreeIterator(repo)); merger.setBase(srcCommit.getTree()); merger.setCommitNames(new String[] { @@ -344,4 +351,23 @@ public RevertCommand setInsertChangeId(boolean insertChangeId) { return this; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @return {@code this} + * @since 7.6 + */ + public RevertCommand setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + return this; + } + + private ConflictStyle getConflictStyle() { + return conflictStyle != null ? conflictStyle + : repo.getConfig().getEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java index b0b715e06b4..aa733b53a67 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java @@ -9,6 +9,9 @@ */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP; import java.io.IOException; @@ -17,6 +20,7 @@ import java.util.List; import java.util.Set; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.JGitInternalException; @@ -76,6 +80,8 @@ public class StashApplyCommand extends GitCommand { private ContentMergeStrategy contentStrategy; + private ConflictStyle conflictStyle; + /** * Create command to apply the changes of a stashed commit * @@ -173,8 +179,7 @@ public ObjectId call() throws GitAPIException, Merger merger = strategy.newMerger(repo); boolean mergeSucceeded; - if (merger instanceof ResolveMerger) { - ResolveMerger resolveMerger = (ResolveMerger) merger; + if (merger instanceof ResolveMerger resolveMerger) { resolveMerger .setCommitNames(new String[] { "stashed HEAD", "HEAD", //$NON-NLS-1$ //$NON-NLS-2$ "stash" }); //$NON-NLS-1$ @@ -182,6 +187,7 @@ public ObjectId call() throws GitAPIException, resolveMerger .setWorkingTreeIterator(new FileTreeIterator(repo)); resolveMerger.setContentMergeStrategy(contentStrategy); + resolveMerger.setConflictStyle(getConflictStyle()); mergeSucceeded = resolveMerger.merge(headCommit, stashCommit); List modifiedByMerge = resolveMerger.getModifiedFiles(); if (!modifiedByMerge.isEmpty()) { @@ -199,12 +205,12 @@ public ObjectId call() throws GitAPIException, dco.checkout(); // Ignoring failed deletes.... if (restoreIndex) { Merger ixMerger = strategy.newMerger(repo, true); - if (ixMerger instanceof ResolveMerger) { - ResolveMerger resolveMerger = (ResolveMerger) ixMerger; + if (ixMerger instanceof ResolveMerger resolveMerger) { resolveMerger.setCommitNames(new String[] { "stashed HEAD", //$NON-NLS-1$ "HEAD", "stashed index" }); //$NON-NLS-1$//$NON-NLS-2$ resolveMerger.setBase(stashHeadCommit); resolveMerger.setContentMergeStrategy(contentStrategy); + resolveMerger.setConflictStyle(getConflictStyle()); } boolean ok = ixMerger.merge(headCommit, stashIndexCommit); if (ok) { @@ -218,8 +224,7 @@ public ObjectId call() throws GitAPIException, if (untrackedCommit != null) { Merger untrackedMerger = strategy.newMerger(repo, true); - if (untrackedMerger instanceof ResolveMerger) { - ResolveMerger resolveMerger = (ResolveMerger) untrackedMerger; + if (untrackedMerger instanceof ResolveMerger resolveMerger) { resolveMerger.setCommitNames(new String[] { "null", "HEAD", //$NON-NLS-1$//$NON-NLS-2$ "untracked files" }); //$NON-NLS-1$ // There is no common base for HEAD & untracked files @@ -230,6 +235,7 @@ public ObjectId call() throws GitAPIException, // commit. resolveMerger.setBase(null); resolveMerger.setContentMergeStrategy(contentStrategy); + resolveMerger.setConflictStyle(getConflictStyle()); } boolean ok = untrackedMerger.merge(headCommit, untrackedCommit); @@ -304,6 +310,25 @@ public StashApplyCommand setContentMergeStrategy( return this; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @return {@code this} + * @since 7.6 + */ + public StashApplyCommand setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + return this; + } + + private ConflictStyle getConflictStyle() { + return conflictStyle != null ? conflictStyle + : repo.getConfig().getEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + /** * Whether the command should restore untracked files * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java index f01158fa79b..0633b23157c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java @@ -195,4 +195,35 @@ public Set getUncommittedChanges() { uncommittedChanges.addAll(diff.getConflicting()); return uncommittedChanges; } + + @SuppressWarnings("nls") + @Override + public String toString() { + if (isClean()) { + return "Working tree is clean"; + } + + StringBuilder sb = new StringBuilder("Git Status [\n"); + + appendSection(sb, "Added", diff.getAdded()); + appendSection(sb, "Modified", diff.getModified()); + appendSection(sb, "Removed", diff.getRemoved()); + appendSection(sb, "Changed", diff.getChanged()); + appendSection(sb, "Missing", diff.getMissing()); + appendSection(sb, "Conflicting", diff.getConflicting()); + appendSection(sb, "Untracked", diff.getUntracked()); + sb.append("]"); + return sb.toString().trim(); + } + + @SuppressWarnings("nls") + private void appendSection(StringBuilder sb, String sectionName, + Set sectionCollection) { + if (!sectionCollection.isEmpty()) { + sb.append(sectionName); + sb.append(" : "); + sb.append(sectionCollection.size()); + sb.append("\n"); + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java index fafc4fb1ecc..8d534e938d2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/ReverseWalk.java @@ -36,8 +36,8 @@ public ReverseCommit next() throws MissingObjectException, } @Override - protected RevCommit createCommit(AnyObjectId id) { - return new ReverseCommit(id); + protected RevCommit createCommit(AnyObjectId id, int graphPos) { + return new ReverseCommit(id, graphPos); } static final class ReverseCommit extends RevCommit { @@ -45,8 +45,8 @@ static final class ReverseCommit extends RevCommit { private ReverseCommit[] children = NO_CHILDREN; - ReverseCommit(AnyObjectId id) { - super(id); + ReverseCommit(AnyObjectId id, int graphPosition) { + super(id, graphPosition); } void addChild(ReverseCommit c) { 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 de02aecdb96..84301c84234 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/Checkout.java @@ -186,12 +186,7 @@ public void checkout(DirCacheEntry entry, CheckoutMetadata metadata, return; } - String name = f.getName(); - if (name.length() > 200) { - name = name.substring(0, 200); - } - File tmpFile = File.createTempFile("._" + name, null, parentDir); //$NON-NLS-1$ - + File tmpFile = createTempFile(f, parentDir); DirCacheCheckout.getContent(cache.getRepository(), path, metadata, ol, options, new FileOutputStream(tmpFile)); @@ -243,4 +238,35 @@ public void checkout(DirCacheEntry entry, CheckoutMetadata metadata, } entry.setLastModified(fs.lastModifiedInstant(f)); } + + /** + * Creates a temp file starting with the prefix "._" followed by the name of + * the given file, truncated to a maximum of 50 characters if necessary. The + * temp file is created in the given parent directory. If the last character + * of the truncated name is a high surrogate, it is removed to avoid + * creating an invalid file name. Some filesystems have a limit of 255 bytes + * for file names, hence the truncation to 50 characters to allow for the + * "._" prefix and potential multi-byte characters. + * + * @param f + * file to create a temp file for + * @param parentDir + * parent directory in which to create the temp file + * @return the temp file created + * @throws IOException + * if an I/O error occurs while creating the temp file + */ + private File createTempFile(File f, File parentDir) throws IOException { + final int MAXLENGTH = 50; + + String name = f.getName(); + if (name.length() > MAXLENGTH) { + if (Character.isHighSurrogate(name.charAt(MAXLENGTH - 1))) { + name = name.substring(0, MAXLENGTH - 1); + } else { + name = name.substring(0, MAXLENGTH); + } + } + return File.createTempFile("._" + name, null, parentDir); //$NON-NLS-1$ + } } \ No newline at end of file diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index 5a229386945..aebea7a583d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -411,9 +411,14 @@ public final boolean mightBeRacilyClean(Instant smudge) { // it is clean or not based on the modification time alone. // final int base = infoOffset + P_MTIME; - final int mtime = NB.decodeInt32(info, base); - if ((int) smudge.getEpochSecond() == mtime) { - return smudge.getNano() <= NB.decodeInt32(info, base + 4); + final int entryMtimeSec = NB.decodeInt32(info, base); + final int smudgeSec = (int) smudge.getEpochSecond(); + if (smudgeSec != 0) { + if (smudgeSec < entryMtimeSec) { + return true; + } else if (smudgeSec == entryMtimeSec) { + return smudge.getNano() <= NB.decodeInt32(info, base + 4); + } } return false; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java index e511a68d2e7..bfc7c9cdc7b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/BareSuperprojectWriter.java @@ -192,6 +192,11 @@ private void prepareIndex(List projects, DirCache index, rec.append(" "); //$NON-NLS-1$ rec.append(group); } + String reviewHost = getPlainHost(proj.getReview()); + if (reviewHost != null && !reviewHost.isEmpty()) { + rec.append(" remote-review="); //$NON-NLS-1$ + rec.append(reviewHost); + } rec.append("\n"); //$NON-NLS-1$ attributes.append(rec.toString()); } @@ -320,4 +325,37 @@ private RevCommit commitTreeOnCurrentTip(ObjectInserter inserter, return rw.parseCommit(commitId); } + + private static String getReviewHost(String reviewUrl) { + if (reviewUrl == null) { + return null; + } + try { + if (!reviewUrl.contains("://")) { //$NON-NLS-1$ + reviewUrl = "https://" + reviewUrl; //$NON-NLS-1$ + } + return URI.create(reviewUrl).getHost(); + } catch (IllegalArgumentException e) { + return null; + } + } + + /** + * Return the host name without "-review" suffix. + * + * @param reviewUrl + * the review URL + * @return host name without "-review" suffix + */ + private static String getPlainHost(String reviewUrl) { + String host = getReviewHost(reviewUrl); + if (host == null) { + return null; + } + int reviewIdx = host.indexOf("-review"); //$NON-NLS-1$ + if (reviewIdx != -1) { + return host.substring(0, reviewIdx); + } + return host; + } } 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 58b4d3dc56a..32234a05a9b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java @@ -44,7 +44,7 @@ /** * Repo XML manifest parser. * - * @see git-repo project page + * @see git-repo project page * @since 4.0 */ public class ManifestParser extends DefaultHandler { @@ -61,6 +61,7 @@ public class ManifestParser extends DefaultHandler { private String defaultRemote; private String defaultRevision; + private String defaultReview; private int xmlInRead; private RepoProject currentProject; @@ -195,7 +196,8 @@ public void startElement( String alias = attributes.getValue("alias"); String fetch = attributes.getValue("fetch"); String revision = attributes.getValue("revision"); - Remote remote = new Remote(fetch, revision); + String review = attributes.getValue("review"); + Remote remote = new Remote(fetch, revision, review); remotes.put(attributes.getValue("name"), remote); if (alias != null) { remotes.put(alias, remote); @@ -204,6 +206,7 @@ public void startElement( case "default": defaultRemote = attributes.getValue("remote"); defaultRevision = attributes.getValue("revision"); + defaultReview = attributes.getValue("review"); break; case "copyfile": if (currentProject == null) { @@ -314,6 +317,12 @@ public void endDocument() throws SAXException { } proj.setUrl(remoteUrl.resolve(proj.getName()).toString()) .setDefaultRevision(revision); + Remote r = remotes.get(remote); + if (r != null && r.review != null) { + proj.setReview(r.review); + } else if (defaultReview != null) { + proj.setReview(defaultReview); + } } filteredProjects.addAll(projects); @@ -440,10 +449,12 @@ private boolean isNestedReferencefile(ReferenceFile referencefile) { private static class Remote { final String fetch; final String revision; + final String review; - Remote(String fetch, String revision) { + Remote(String fetch, String revision, String review) { this.fetch = fetch; this.revision = revision; + this.review = review; } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index be77fca459c..32f2ad1bf0a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -58,7 +58,7 @@ * work in git submodule, so we'll skip all the sub projects * ("foo/bar" in the example) while converting. * - * @see git-repo project page + * @see git-repo project page * @since 3.4 */ public class RepoCommand extends GitCommand { @@ -591,6 +591,7 @@ private List renameProjects(List projects) { p.addCopyFiles(proj.getCopyFiles()); p.addLinkFiles(proj.getLinkFiles()); p.setUpstream(proj.getUpstream()); + p.setReview(proj.getReview()); ret.add(p); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java index 2630da34e05..97f461c319f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java @@ -27,7 +27,7 @@ /** * The representation of a repo sub project. * - * @see git-repo project page + * @see git-repo project page * @since 4.0 */ public class RepoProject implements Comparable { @@ -41,6 +41,7 @@ public class RepoProject implements Comparable { private String upstream; private String destBranch; private String recommendShallow; + private String review; private String url; private String defaultRevision; @@ -332,6 +333,27 @@ public void setRecommendShallow(String recommendShallow) { this.recommendShallow = recommendShallow; } + /** + * Return the Gerrit review server URL defined by the project's remote. + * + * @return the review server URL + * @since 7.8 + */ + public String getReview() { + return review; + } + + /** + * Sets the Gerrit review server URL. + * + * @param review the review server URL + * @since 7.8 + */ + public void setReview(String review) { + this.review = review; + } + + /** * Add a copy file configuration. * 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 1f496299f30..5bab3537482 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -147,6 +147,7 @@ public static JGitText get() { /***/ public String cannotMoveIndexTo; /***/ public String cannotMovePackTo; /***/ public String cannotOpenService; + /***/ public String cannotOpenMidx; /***/ public String cannotParseDate; /***/ public String cannotParseGitURIish; /***/ public String cannotPullOnARepoWithState; @@ -290,6 +291,7 @@ public static JGitText get() { /***/ public String deepenSinceWithDeepen; /***/ public String deleteBranchUnexpectedResult; /***/ public String deleteFileFailed; + /***/ public String deleteLooseRef; /***/ public String deletedOrphanInPackDir; /***/ public String deleteRequiresZeroNewId; /***/ public String deleteTagUnexpectedResult; @@ -543,6 +545,7 @@ public static JGitText get() { /***/ public String messageAndTaggerNotAllowedInUnannotatedTags; /***/ public String midxChunkNeeded; /***/ public String midxChunkRepeated; + /***/ public String midxChunkTooBig; /***/ public String midxChunkUnknown; /***/ public String minutesAgo; /***/ public String mismatchOffset; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/BitmappedObjectReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/BitmappedObjectReachabilityChecker.java index d8056490aa4..31d17ad2f22 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/BitmappedObjectReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/BitmappedObjectReachabilityChecker.java @@ -69,7 +69,7 @@ public Optional areAllReachable(Collection targets, true); seen = seen == null ? visited : seen.or(visited); - remainingTargets.removeIf(seen::contains); + remainingTargets.removeIf(visited::contains); if (remainingTargets.isEmpty()) { return Optional.empty(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/RefAdvancerWalk.java similarity index 77% rename from org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalk.java rename to org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/RefAdvancerWalk.java index d0d80562f5d..714ccf79a29 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/RefAdvancerWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/revwalk/RefAdvancerWalk.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: BSD-3-Clause */ -package org.eclipse.jgit.internal.storage.dfs; +package org.eclipse.jgit.internal.revwalk; import java.io.IOException; import java.util.HashSet; @@ -16,6 +16,7 @@ import org.eclipse.jgit.errors.StopWalkException; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevSort; @@ -25,21 +26,38 @@ /** * Walk from some commits and find where to they enter a pack */ -class RefAdvancerWalk { +public class RefAdvancerWalk { - private final DfsRepository db; + private final Repository db; private final InPackPredicate includeP; /** - * True when the commit is in the pack + * True when the commit is in the target set */ @FunctionalInterface - interface InPackPredicate { + public interface InPackPredicate { + /** + * Check if the commit belongs to the "pack" (target set of objects) + * + * @param c + * a commit + * @return true if the commit is in the set + * @throws IOException + * an error reading data + */ boolean test(RevCommit c) throws IOException; } - RefAdvancerWalk(DfsRepository db, InPackPredicate include) { + /** + * Constructor + * + * @param db + * a repository + * @param include + * predicate telling if a commit in the target set + */ + public RefAdvancerWalk(Repository db, InPackPredicate include) { this.db = db; this.includeP = include; } @@ -64,7 +82,7 @@ private RevWalk createRevWalk() { * @throws IOException * error browsing history */ - Set advance(List allTips) throws IOException { + public Set advance(List allTips) throws IOException { Set tipsInMidx = new HashSet<>(allTips.size()); try (RevWalk rw = createRevWalk()) { for (ObjectId tip : allTips) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java index 654bc30225f..32b4d14c3c8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java @@ -13,11 +13,11 @@ import static java.util.stream.Collectors.toMap; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -25,17 +25,22 @@ import java.util.function.Function; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.internal.revwalk.RefAdvancerWalk; import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder; -import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex; import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter; +import org.eclipse.jgit.internal.storage.midx.PackIndexMerger; +import org.eclipse.jgit.internal.storage.pack.ObjectToPack; import org.eclipse.jgit.internal.storage.pack.PackBitmapCalculator; import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdOwnerMap; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.pack.PackConfig; +import org.eclipse.jgit.util.Base64; /** * Create a pack with a multipack index, setting the required fields in the @@ -46,30 +51,6 @@ public class DfsMidxWriter { private DfsMidxWriter() { } - /** - * Create a pack with the multipack index (without bitmaps). - * - * @param pm - * a progress monitor - * @param objdb - * an object database - * @param packs - * the packs to cover - * @param base - * parent of this midx in the chain (if any). - * - * @return a pack (uncommitted) with the multipack index of the packs passed - * as parameter. - * @throws IOException - * an error opening the packs or writing the stream. - */ - public static DfsPackDescription writeMidx(ProgressMonitor pm, - DfsObjDatabase objdb, List packs, - @Nullable DfsPackDescription base) throws IOException { - return writeMidx(pm, objdb, packs, base, - new PackConfig(objdb.getRepository())); - } - /** * Create a pack with the multipack index * @@ -82,7 +63,8 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm, * @param base * parent of this midx in the chain (if any). * @param packConfig - * pack config with the parameters to write bitmaps. + * pack config with parameter to build bitmaps. Null to disable + * bitmaps. * @return a pack (uncommitted) with the multipack index of the packs passed * as parameter. * @throws IOException @@ -90,25 +72,35 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm, */ public static DfsPackDescription writeMidx(ProgressMonitor pm, DfsObjDatabase objdb, List packs, - @Nullable DfsPackDescription base, PackConfig packConfig) + @Nullable DfsPackDescription base, @Nullable PackConfig packConfig) throws IOException { - LinkedHashMap inputs = new LinkedHashMap<>( - packs.size()); + PackIndexMerger.Builder dataBuilder = PackIndexMerger.builder(); try (DfsReader ctx = objdb.newReader()) { for (DfsPackFile pack : packs) { - inputs.put(pack.getPackDescription().getPackName(), + if (pack instanceof DfsPackFileMidx) { + // asObjectsToPack assumes one packid per pack while + // calculating midx offsets. We need to fix that before + // accepting midx to build new midx. + throw new IOException( + "MIDX not supported to build new midx"); //$NON-NLS-1$ + } + dataBuilder.addPack(pack.getPackDescription().getPackName(), pack.getPackIndex(ctx)); } } + PackIndexMerger data = dataBuilder.build(); + byte[] checksum; + DfsPackDescription midxPackDesc = objdb.newPack(GC); try (DfsOutputStream out = objdb.writeFile(midxPackDesc, MULTI_PACK_INDEX)) { MultiPackIndexWriter w = new MultiPackIndexWriter(); - MultiPackIndexWriter.Result result = w.write(pm, out, inputs); + MultiPackIndexWriter.Result result = w.write(pm, out, data); midxPackDesc.addFileExt(MULTI_PACK_INDEX); midxPackDesc.setFileSize(MULTI_PACK_INDEX, result.bytesWritten()); midxPackDesc.setObjectCount(result.objectCount()); + checksum = Base64.decode(result.checksum()); Map byName = packs.stream() .map(DfsPackFile::getPackDescription) @@ -122,11 +114,10 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm, } } - // TODO(ifrade): At the moment write bitmaps only in the bottom midx. - // A single-pack midx in the base should be covering only GC. No - // need to write midx bitmaps (we will use GC bitmaps). - if (base == null && midxPackDesc.getCoveredPacks().size() > 1) { + // TODO(ifrade): At the moment we only support bitmaps on the base + if (base == null && packConfig != null) { createAndAttachBitmaps(objdb.getRepository(), midxPackDesc, + checksum, data, packs, packConfig); } @@ -134,12 +125,8 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm, } private static void createAndAttachBitmaps(DfsRepository db, - DfsPackDescription desc, PackConfig cfg) throws IOException { - - DfsObjDatabase objdb = db.getObjectDatabase(); - // We need a DfsPackFile to reread the contents - DfsPackFileMidx midxPack = db.getObjectDatabase().createDfsPackFileMidx( - DfsBlockCache.getInstance(), desc, new ArrayList<>()); + DfsPackDescription desc, byte[] checksum, PackIndexMerger data, + List packs, PackConfig cfg) throws IOException { // TODO(ifrade): Verify we duplicate the behaviour about tags of regular // bitmapping @@ -150,14 +137,16 @@ private static void createAndAttachBitmaps(DfsRepository db, return; } - try (DfsReader ctx = objdb.newReader()) { + try (DfsReader ctx = db.getObjectDatabase().newReader()) { + ObjectIdOwnerMap byId = new ObjectIdOwnerMap<>(); + List otps = asObjectsToPack(ctx, data, packs, byId); + RefAdvancerWalk adv = new RefAdvancerWalk(db, - c -> midxPack.hasObject(ctx, c)); + c -> byId.contains(c)); Set inPack = adv.advance(allHeads); - byte[] checksum = midxPack.getChecksum(ctx); PackBitmapIndexBuilder writeBitmaps = new PackBitmapIndexBuilder( - midxPack.getLocalObjects(ctx)); + otps); int commitCount = writeBitmaps.getCommits().cardinality(); PackBitmapCalculator calculator = new PackBitmapCalculator(cfg); @@ -170,4 +159,30 @@ private static void createAndAttachBitmaps(DfsRepository db, } } + private static List asObjectsToPack(DfsReader ctx, + PackIndexMerger data, List packs, + ObjectIdOwnerMap byId) throws IOException { + long[] accPackSize = new long[packs.size()]; + for (int i = 1; i < packs.size(); i++) { + long prevValue = accPackSize[i - 1]; + accPackSize[i] = prevValue + + packs.get(i - 1).getPackDescription().getFileSize(PACK); + } + + List result = new ArrayList<>( + data.getUniqueObjectCount()); + MultiPackIndex.MidxIterator it = data.bySha1Iterator(); + while (it.hasNext()) { + MultiPackIndex.MutableEntry entry = it.next(); + int objectType = packs.get(entry.getPackId()).getObjectType(ctx, + entry.getOffset()); + ObjectToPack o = new ObjectToPack(entry.getObjectId().toObjectId(), + objectType); + o.setOffset(accPackSize[entry.getPackId()] + entry.getOffset()); + result.add(o); + byId.add(o); + } + return result; + } + } 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 fc6596e843f..8c96e85a16f 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 @@ -612,19 +612,36 @@ PackList scanPacks(PackList original) throws IOException { } private PackList scanPacksImpl(PackList old) throws IOException { - DfsBlockCache cache = DfsBlockCache.getInstance(); - Map packs = packMap(old); - Map reftables = reftableMap(old); - List scanned = useMultipackIndex() ? MidxPackFilter.useMidx(listPacks()) : MidxPackFilter.skipMidxs(listPacks()); scanned.sort(packComparator); + return descTreeToPackList(scanned, old); + } + + /** + * Translate the valid list of descriptions (with midx as trees of packs) + * into DfsPackFile and DfsReftable instances + * + * @param descTree + * a valid list of descriptions, may contain midx. Covered packs + * and nested midxs are NOT in the top level list. + * @return a packlist with the new/reused DfsPackFile instances + */ + public PackList descTreeToPackList(List descTree) { + return descTreeToPackList(descTree, NO_PACKS); + } - List newPacks = new ArrayList<>(scanned.size()); + private PackList descTreeToPackList(List descTree, + PackList old) { + Map packs = packMap(old); + Map reftables = reftableMap(old); + + DfsBlockCache cache = DfsBlockCache.getInstance(); + List newPacks = new ArrayList<>(descTree.size()); List packsWithReftables = new ArrayList<>(); boolean foundNew = false; - for (DfsPackDescription dsc : scanned) { + for (DfsPackDescription dsc : descTree) { DfsPackFile oldPack = packs.remove(dsc); if (oldPack != null) { newPacks.add(oldPack); @@ -677,7 +694,7 @@ private PackList scanPacksImpl(PackList old) throws IOException { * pack description * @return the dfs packfile */ - protected DfsPackFile createDfsPackFile(DfsBlockCache cache, + public DfsPackFile createDfsPackFile(DfsBlockCache cache, DfsPackDescription dsc) { return new DfsPackFile(cache, dsc); } 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 8860cce0382..fbe641ec51d 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 @@ -26,6 +26,7 @@ import java.util.List; import java.util.Set; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.PackIndex; @@ -78,6 +79,62 @@ public class DfsPackCompactor { private RevFlag added; private RevFlag isBase; + /** + * Hook invoked after the compact calculation is done, but before committing + * the resulting packs. + *

+ * The hook implementations must not modify the incoming collections. + * Instead, they should return any extra packs to commit or remove in a + * {@link Packs} record, which the caller will combine with the calculated + * results. + */ + public interface PreCommitHook { + /** + * Extra packs to commit and remove as result of the hook execution. + * + * @param toCommit + * packs that this hook wants to add to the compactor + * transaction + * @param toRemove + * packs that this hook wants to remove in the compactor + * transaction + */ + record Packs(List toCommit, + List toRemove) { + } + + /** + * Apply the hook. + * + * @param newPacks + * new packs created by this compaction. Read only. + * @param removedPacks + * packs that are being replaced by this compaction. Read + * only. + * @return Packs containing extra packs to commit and remove, or null if + * none. + * @throws IOException + * an error occurred in the hook. + */ + @Nullable + Packs apply(List newPacks, + Set removedPacks) throws IOException; + } + + private PreCommitHook preCommitHook; + + /** + * Set the pre-commit hook. + * + * @param hook + * pre-commit hook. + * @return {@code this} + */ + public DfsPackCompactor setPreCommitHook(PreCommitHook hook) { + this.preCommitHook = hook; + return this; + } + /** * Initialize a pack compactor. * @@ -196,8 +253,15 @@ public void compact(ProgressMonitor pm) throws IOException { } compactPacks(ctx, pm); - List commit = getNewPacks(); - Collection remove = toPrune(); + List commit = new ArrayList<>(getNewPacks()); + Set remove = toPrune(); + if (preCommitHook != null) { + PreCommitHook.Packs extra = preCommitHook.apply(commit, remove); + if (extra != null) { + commit.addAll(extra.toCommit()); + remove.addAll(extra.toRemove()); + } + } if (!commit.isEmpty() || !remove.isEmpty()) { objdb.commitPack(commit, remove); } @@ -318,7 +382,7 @@ public List getNewPackStatistics() { : Collections.emptyList(); } - private Collection toPrune() { + private Set toPrune() { Set packs = new HashSet<>(); for (DfsPackFile pack : srcPacks) { packs.add(pack.getPackDescription()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java index d4fe5669d88..7a3c1396b0f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java @@ -366,6 +366,19 @@ public long getFileSize(PackExt ext) { return i < sizeMap.length ? sizeMap[i] : 0; } + /** + * Get total size of the pack, including indexes + * + * @return the size of the pack and all its extensions + */ + public long getTotalFileSize() { + long result = 0; + for (long sz : sizeMap) { + result += sz; + } + return result; + } + /** * Get blockSize of the file, in bytes. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java index 0582737753a..402bb24247b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java @@ -20,6 +20,7 @@ import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException; import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.internal.storage.file.PackReverseIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex; import org.eclipse.jgit.internal.storage.pack.ObjectToPack; import org.eclipse.jgit.internal.storage.pack.PackOutputStream; import org.eclipse.jgit.lib.AbbreviatedObjectId; @@ -56,7 +57,12 @@ public static DfsPackFileMidx create(DfsBlockCache cache, DfsPackDescription desc, List requiredPacks, @Nullable DfsPackFileMidx base) { if (desc.getCoveredPacks().size() == 1) { - return new DfsPackFileMidxSingle(cache, desc, requiredPacks.get(0), + String coveredPackName = desc.getCoveredPacks().get(0) + .getPackName(); + DfsPackFile coveredPack = requiredPacks.stream().filter(p -> p + .getPackDescription().getPackName().equals(coveredPackName)) + .findFirst().orElseThrow(); + return new DfsPackFileMidxSingle(cache, desc, coveredPack, base); } return new DfsPackFileMidxNPacks(cache, desc, requiredPacks, base); @@ -84,9 +90,10 @@ protected DfsPackFileMidx(DfsBlockCache cache, DfsPackDescription desc) { public abstract DfsPackFileMidx getMultipackIndexBase(); /** - * Packs indexed by this multipack index (base NOT included) + * Packs indexed by this multipack index (base NOT included) in midx order. * - * @return packs indexed by this multipack index + * @return packs indexed by this multipack index in the order used inside + * the midx. */ public abstract List getCoveredPacks(); @@ -152,6 +159,18 @@ protected int getObjectCount(DfsReader ctx) throws IOException { */ protected abstract byte[] getChecksum(DfsReader ctx) throws IOException; + /** + * Get a midx iterator over the contents of *this* midx, without the base. + * + * @param ctx + * a ready + * @return an iterator over the objects in this midx in sha1 order + * @throws IOException + * an error loading the underlying data + */ + protected abstract MultiPackIndex.MidxIterator localIterator(DfsReader ctx) + throws IOException; + @Override public final PackIndex getPackIndex(DfsReader ctx) { return new MidxPackIndex(this, ctx); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java index bed7a534999..f042f2e61ec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxNPacks.java @@ -52,8 +52,6 @@ public final class DfsPackFileMidxNPacks extends DfsPackFileMidx { private static final int REF_POSITION = 0; - private final List packs; - // The required packs, in the order specified in the multipack index // Initialized lazily, when the midx is loaded private final DfsPackFile[] packsInIdOrder; @@ -64,14 +62,27 @@ public final class DfsPackFileMidxNPacks extends DfsPackFileMidx { private final VOffsetCalculatorNPacks offsetCalculator; + /** + * Create the DfsPackFileMidx instance for this midx with n packs + * + * @param cache + * dfs block cache + * @param desc + * description of the midx + * @param knownPacks + * known packs, to translate the pack names in coveredPacks into + * DfsPackFile instances. It must contain at least all packs + * covered by this midx. + * @param base + * base used by this midx. + */ DfsPackFileMidxNPacks(DfsBlockCache cache, DfsPackDescription desc, - List requiredPacks, @Nullable DfsPackFileMidx base) { + List knownPacks, @Nullable DfsPackFileMidx base) { super(cache, desc); this.base = base; - this.packs = requiredPacks; String[] coveredPackNames = desc.getCoveredPacks().stream() .map(DfsPackDescription::getPackName).toArray(String[]::new); - packsInIdOrder = getPacksInMidxIdOrder(coveredPackNames); + packsInIdOrder = getPacksInMidxIdOrder(knownPacks, coveredPackNames); offsetCalculator = VOffsetCalculatorNPacks.fromPacks(packsInIdOrder, base != null ? base.getOffsetCalculator() : null); this.length = offsetCalculator.getMaxOffset(); @@ -114,8 +125,9 @@ private static RefWithSize loadMultiPackIndex(DfsReader ctx, private record RefWithSize(MultiPackIndex idx, long size) { } - private DfsPackFile[] getPacksInMidxIdOrder(String[] packNames) { - Map byName = packs.stream() + private DfsPackFile[] getPacksInMidxIdOrder(List knownPacks, + String[] packNames) { + Map byName = knownPacks.stream() .collect(Collectors.toUnmodifiableMap( p -> p.getPackDescription().getPackName(), Function.identity())); @@ -170,7 +182,7 @@ && getPackDescription().hasFileExt(BITMAP_INDEX)) { List fullyIncludedIn(DfsReader ctx, BitmapIndex.BitmapBuilder need) throws IOException { List fullyIncluded = new ArrayList<>(); - for (DfsPackFile pack : packs) { + for (DfsPackFile pack : packsInIdOrder) { List includedPacks = pack.fullyIncludedIn(ctx, need); if (!includedPacks.isEmpty()) { fullyIncluded.addAll(includedPacks); @@ -186,7 +198,7 @@ List fullyIncludedIn(DfsReader ctx, @Override public CommitGraph getCommitGraph(DfsReader ctx) throws IOException { - for (DfsPackFile pack : packs) { + for (DfsPackFile pack : packsInIdOrder) { CommitGraph cg = pack.getCommitGraph(ctx); if (cg != null) { return cg; @@ -242,6 +254,12 @@ protected byte[] getChecksum(DfsReader ctx) throws IOException { return midx(ctx).getChecksum(); } + @Override + protected MultiPackIndex.MidxIterator localIterator(DfsReader ctx) + throws IOException { + return midx(ctx).iterator(); + } + /** * Packs indexed by this multipack index (base NOT included) * @@ -249,7 +267,7 @@ protected byte[] getChecksum(DfsReader ctx) throws IOException { */ @Override public List getCoveredPacks() { - return packs; + return List.of(packsInIdOrder); } /** @@ -344,7 +362,7 @@ void resolve(DfsReader ctx, Set matches, AbbreviatedObjectId id, @Override void copyPackAsIs(PackOutputStream out, DfsReader ctx) throws IOException { // Assumming the order of the packs does not really matter - for (DfsPackFile pack : packs) { + for (DfsPackFile pack : packsInIdOrder) { pack.copyPackAsIs(out, ctx); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java index 71ff884cda7..89dbf9daf49 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxSingle.java @@ -25,6 +25,8 @@ 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.midx.MidxIterators; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex; import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.PackOffset; import org.eclipse.jgit.internal.storage.pack.ObjectToPack; import org.eclipse.jgit.internal.storage.pack.PackExt; @@ -149,6 +151,14 @@ protected byte[] getChecksum(DfsReader ctx) throws IOException { return checksum; } + @Override + protected MultiPackIndex.MidxIterator localIterator(DfsReader ctx) + throws IOException { + String packName = pack.getPackDescription().getPackName(); + PackIndex packIndex = pack.getPackIndex(ctx); + return MidxIterators.fromPackIndexIterator(packName, packIndex); + } + /** * Packs indexed by this multipack index (base NOT included) * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java index f48572550fd..d60ca1e45b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java @@ -21,6 +21,7 @@ import java.util.Queue; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; import org.eclipse.jgit.annotations.Nullable; @@ -41,18 +42,23 @@ public final class MidxPackList { * list of packs (regular or tip midxs) * @return a MidxPackList instance */ - public static MidxPackList create(DfsPackFile[] packs) { - return new MidxPackList(packs); + public static MidxPackList create(DfsPackFile... packs) { + return new MidxPackList(Arrays.asList(packs)); } private final List packs; - private MidxPackList(DfsPackFile[] packs) { - this.packs = Arrays.asList(packs); + private MidxPackList(List packs) { + this.packs = packs; } /** * Get all plain packs in the list, either top-level or inside midxs + *

+ * Inside midx, the packs are in reverse lookup order. This code restores + * their original order. i.e. the list with packs [INSERT, midx(COMPACT-2, + * COMPACT-3), midx(GC, COMPACT-1)] becomes [INSERT, COMPACT-3, COMPACT-2, + * COMPACT-1, GC]. * * @return a list of all "real" packs in this pack list, either top level or * inside midxs. @@ -63,7 +69,11 @@ public List getAllPlainPacks() { while (!pending.isEmpty()) { DfsPackFile pack = pending.poll(); if (pack instanceof DfsPackFileMidx midxPack) { - plainPacks.addAll(midxPack.getCoveredPacks()); + // Midx order is the reverse of object lookup order + ArrayList coveredPacks = new ArrayList<>( + midxPack.getCoveredPacks()); + Collections.reverse(coveredPacks); + plainPacks.addAll(coveredPacks); if (midxPack.getMultipackIndexBase() != null) { pending.add(midxPack.getMultipackIndexBase()); } @@ -104,8 +114,8 @@ public List getAllMidxPacks() { * a single pack * @return all the midxs that include (directly or indirectly) the pack */ - Set findAllCoveringMidxs(DfsPackFile pack) { - return findAllCoveringMidxs(List.of(pack)); + Set findAllCoveringMidxs(DfsPackFile... pack) { + return findAllCoveringMidxs(Arrays.asList(pack)); } /** @@ -200,6 +210,151 @@ public List getPlainPacksNotCoveredBy( .toList(); } + /** + * Get a builder to add/remove packs from the list + * + * @return the builder + */ + public Builder edit() { + return new Builder(packs); + } + + /** + * Builder to mutate the list of packs. + * + * It removes midxs from the list as packs are removed, to maintain a valid + * view of the packlist + */ + public final static class Builder { + + private final List packList; + + private Builder(List packs) { + this.packList = new ArrayList<>(packs); + } + + /** + * Add pack to the packlist + * + * @param toAdd + * pack to add + * @return this builder + */ + public Builder add(DfsPackFile toAdd) { + packList.add(toAdd); + return this; + } + + /** + * Delete the pack from the pack list + * + * Including any midx covering it directly or indirectly + * + * @param toDelete + * a pack to remove from the list + * @return this builder + */ + public Builder delete(DfsPackFile toDelete) { + // Check first top-level packs. In compact these are the most + // common packages being replaced. + DfsPackDescription toDeleteDesc = toDelete.getPackDescription(); + for (int i = 0; i < packList.size(); i++) { + if (packList.get(i).getPackDescription().equals(toDeleteDesc)) { + packList.remove(i); + return this; + } + } + + // If the pack is not "top-level", it may be covered by midx. + // We need to remove the pack, its covering midxs, but keep the + // other covered packs in their place. + // e.g. in the chain midx3(E, F) -> midx2 (C, D), -> midx(A, B), + // deleting C from midx3 produces: [F, E, D, midx(A, B)] + for (int i = packList.size() - 1; i >= 0; i--) { + if (!packList.get(i).getPackDescription() + .hasFileExt(MULTI_PACK_INDEX)) { + continue; + } + + DfsPackFileMidx midx = (DfsPackFileMidx) packList.get(i); + if (!containsAny(midx.getAllCoveredPacks(), + List.of(toDelete))) { + continue; + } + + List replacement = getPacksToReplaceMidx(midx, + toDelete); + if (replacement != null) { + packList.remove(i); + if (!replacement.isEmpty()) { + packList.addAll(i, replacement); + } + } + } + + return this; + } + + /** + * Return the list of packs that replace a midx if we remove a pack + * + * When the pack is removed, any midx covering it (and above in the + * chain) is invalid. Each invalid midx is replaced with its covered + * packs (excluding the deleted pack) + * + * @param midx + * the midx + * @param toDelete + * the pack to remove + * @return the resulting list of packs after removing the pack. It can + * be null (nothing to change), empty (replace with nothing, + * i.e. delete the midx) or a list of packs + */ + @Nullable + private List getPacksToReplaceMidx(DfsPackFileMidx midx, + DfsPackFile toDelete) { + List result = new ArrayList<>(); + DfsPackFileMidx current = midx; + while (current != null) { + if (containsAny(current.getCoveredPacks(), List.of(toDelete))) { + List otherCovered = current.getCoveredPacks() + .stream() + .filter(coveredPack -> !coveredPack + .getPackDescription() + .equals(toDelete.getPackDescription())) + .collect(Collectors.toCollection(ArrayList::new)); + Collections.reverse(otherCovered); + result.addAll(otherCovered); + if (current.getMultipackIndexBase() != null) { + result.add(current.getMultipackIndexBase()); + } + return result; + } + + // The deleted pack must be in the base of this midx, and it + // wil invalidate this one. Add all its covered packs to the + // result. + List tmp = new ArrayList<>( + current.getCoveredPacks()); + Collections.reverse(tmp); + result.addAll(tmp); + current = current.getMultipackIndexBase(); + } + + // We didn't find the pack to delete in this midx chain + return null; + } + + /** + * Create a new pack list with the modifications + * + * @return a new packlist with the changes applied + */ + public MidxPackList build() { + return new MidxPackList(packList); + } + } + private static boolean containsAny(List inMidx, List queryPacks) { Set inMidxSet = asSet(inMidx); 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 6a7827160ca..7885794fcac 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 @@ -1995,6 +1995,9 @@ private String getProcDesc() { } private long getPID() { + if (SystemReader.getInstance().isAndroid()) { + return 0; + } return ProcessHandle.current().pid(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java new file mode 100644 index 00000000000..ce610c139f7 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2026, 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.file; + +import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.jgit.internal.revwalk.RefAdvancerWalk; +import org.eclipse.jgit.internal.storage.midx.MidxMetadataReader; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter; +import org.eclipse.jgit.internal.storage.midx.PackIndexMerger; +import org.eclipse.jgit.internal.storage.pack.ObjectToPack; +import org.eclipse.jgit.internal.storage.pack.PackBitmapCalculator; +import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdOwnerMap; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.eclipse.jgit.util.Base64; +import org.eclipse.jgit.util.FileUtils; + +/** + * Helper to write multipack indexes. + */ +public class MidxWriter { + + /** + * Do not build a midx if there are less than this amount of packs to cover. + */ + private static final int MIN_PACKS_FOR_MIDX = 2; + + /** + * Write a mdix over the packs + * + * @param pm + * a progress monitor + * @param repo + * the repository + * @param packs + * packs to cover with the midx + * @param midxOut + * file to write the resulting midx + * @param packConfig + * config for the bitmap writing. Null to skip writing bitmaps. + * @throws IOException + * an error reading any of the input packs or indexes + */ + public static void writeMidx(ProgressMonitor pm, Repository repo, + Collection packs, File midxOut, PackConfig packConfig) + throws IOException { + + List packList = flattenMidxPackList(packs).stream() + .sorted(Comparator.comparing(Pack::getPackName)).toList(); + if (packList.size() < MIN_PACKS_FOR_MIDX) { + return; + } + PackIndexMerger.Builder builder = PackIndexMerger.builder(); + builder.setProgressMonitor(pm); + pm.beginTask("Adding packs to midx", packList.size()); //$NON-NLS-1$ + for (Pack pack : packList) { + if (pack instanceof PackMidx) { + throw new IllegalArgumentException( + "Building midx from other midx not supported yet"); + } + PackFile packFile = pack.getPackFile().create(PackExt.INDEX); + builder.addPack(packFile.getName(), pack.getIndex()); + + pm.update(1); + } + PackIndexMerger data = builder.build(); + pm.endTask(); + + File oldMidxBitmaps = null; + if (midxOut.exists()) { + MidxMetadataReader.MidxMetadata midxMetadata = MidxMetadataReader + .read(midxOut); + byte[] checksum = midxMetadata.checksum(); + String midxBitmapsPath = midxOut.getAbsoluteFile() + "-" //$NON-NLS-1$ + + ObjectId.fromRaw(checksum).name() + "." //$NON-NLS-1$ + + BITMAP_INDEX.getExtension(); + File previousBitmaps = new File(midxBitmapsPath); + if (previousBitmaps.exists()) { + oldMidxBitmaps = previousBitmaps; + } + } + + String midxFilename = midxOut.getAbsolutePath(); + File midxOutTmp = new File( + midxFilename + BITMAP_INDEX.getTmpExtension()); + MultiPackIndexWriter writer = new MultiPackIndexWriter(); + MultiPackIndexWriter.Result result; + try (FileOutputStream out = new FileOutputStream( + midxOutTmp.getAbsolutePath())) { + result = writer.write(pm, out, data); + } + + File midxOutBitmaps = new File(midxOut.getAbsoluteFile() + "-" //$NON-NLS-1$ + + ObjectId.fromRaw(Base64.decode(result.checksum())).name() + + "." + BITMAP_INDEX.getExtension()); + File midxOutBitmapsTmp = null; + if (packConfig != null) { + midxOutBitmapsTmp = new File(midxOut.getAbsolutePath() + "-" //$NON-NLS-1$ + + ObjectId.fromRaw(Base64.decode(result.checksum())).name() + + BITMAP_INDEX.getTmpExtension()); + createAndAttachBitmaps(pm, repo, midxOutBitmapsTmp, + Base64.decode(result.checksum()), data, packList, + new PackConfig(repo)); + } + + FileUtils.rename(midxOutTmp.getAbsoluteFile(), + midxOut.getAbsoluteFile(), StandardCopyOption.ATOMIC_MOVE); + if (midxOutBitmapsTmp != null) { + FileUtils.rename(midxOutBitmapsTmp.getAbsoluteFile(), + midxOutBitmaps.getAbsoluteFile(), + StandardCopyOption.ATOMIC_MOVE); + } + + if (oldMidxBitmaps != null && !oldMidxBitmaps.equals(midxOutBitmaps)) { + FileUtils.delete(oldMidxBitmaps); + } + } + + private static void createAndAttachBitmaps(ProgressMonitor pm, + Repository repo, File midxBitmapsOut, byte[] checksum, + PackIndexMerger data, Collection packs, PackConfig cfg) + throws IOException { + + // TODO(ifrade): Verify we duplicate the behaviour about tags of regular + // bitmapping + List allHeads = repo.getRefDatabase() + .getRefsByPrefix(Constants.R_HEADS).stream() + .map(Ref::getObjectId).filter(Objects::nonNull).toList(); + if (allHeads.isEmpty()) { + return; + } + + ObjectIdOwnerMap byId = new ObjectIdOwnerMap<>(); + List otps = asObjectsToPack(pm, + (WindowCursor) repo.newObjectReader(), data, + new ArrayList<>(packs), byId); + + RefAdvancerWalk adv = new RefAdvancerWalk(repo, byId::contains); + Set inPack = adv.advance(allHeads); + + PackBitmapIndexBuilder writeBitmaps = new PackBitmapIndexBuilder(otps); + int commitCount = writeBitmaps.getCommits().cardinality(); + + PackBitmapCalculator calculator = new PackBitmapCalculator(cfg); + // This will do ctx.getBitmapIndex() to reuse/copy previous bitmaps + calculator.calculate(repo.newObjectReader(), + NullProgressMonitor.INSTANCE, commitCount, inPack, + new HashSet<>(), writeBitmaps); + try (FileOutputStream out = new FileOutputStream( + midxBitmapsOut.getAbsolutePath())) { + PackBitmapIndexWriter pbiWriter = new PackBitmapIndexWriterV1(out); + pbiWriter.write(writeBitmaps, checksum); + } + } + + private static List asObjectsToPack(ProgressMonitor pm, + WindowCursor ctx, PackIndexMerger data, List packs, + ObjectIdOwnerMap byId) throws IOException { + long[] accPackSize = new long[packs.size()]; + for (int i = 1; i < packs.size(); i++) { + long prevValue = accPackSize[i - 1]; + accPackSize[i] = prevValue + + packs.get(i - 1).getPackFile().length(); + } + + pm.beginTask("Converting midx to ObjectsToPack", //$NON-NLS-1$ + data.getUniqueObjectCount()); + List result = new ArrayList<>( + data.getUniqueObjectCount()); + MultiPackIndex.MidxIterator it = data.bySha1Iterator(); + while (it.hasNext()) { + MultiPackIndex.MutableEntry entry = it.next(); + int objectType = packs.get(entry.getPackId()).getObjectType(ctx, + entry.getOffset()); + ObjectToPack o = new ObjectToPack(entry.getObjectId().toObjectId(), + objectType); + o.setOffset(accPackSize[entry.getPackId()] + entry.getOffset()); + result.add(o); + byId.add(o); + pm.update(1); + } + pm.endTask(); + return result; + } + + static List flattenMidxPackList(Collection packs) { + List output = new ArrayList<>(); + for (Pack p : packs) { + List coveredPacks = new ArrayList<>(p.getCoveredPacks()); + if (coveredPacks.isEmpty()) { + output.add(p); + } else { + Collections.reverse(coveredPacks); + output.addAll(coveredPacks); + } + } + return Collections.unmodifiableList(output); + } +} 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 8988b41b55e..7aaf81798f4 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 @@ -14,10 +14,10 @@ import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP; +import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.REVERSE_INDEX; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PACKED_INDEX_GIT_USE_STRONGREFS; -import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import java.io.EOFException; import java.io.File; @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -61,6 +62,7 @@ import org.eclipse.jgit.internal.util.Optionally; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BitmapIndex; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -169,6 +171,28 @@ public Pack(Config cfg, File packFile, @Nullable PackFile bitmapIdxFile) { length = Long.MAX_VALUE; } + /** + * Set the checksum of this pack + * + * @param checksum + * the checksum + */ + protected void setPackChecksum(byte[] checksum) { + this.packChecksum = checksum; + } + + /** + * Packs covered by this pack + *

+ * For regular packs, this list is empty. For midx packs, this list has the + * names of packs indexed by the midx. + * + * @return list of packs covered by this pack. + */ + protected List getCoveredPacks() { + return Collections.emptyList(); + } + private PackIndex idx() throws IOException { Optional optional = loadedIdx.getOptional(); if (optional.isPresent()) { @@ -198,10 +222,9 @@ private synchronized PackIndex memoizeIdxIfNeeded() throws IOException { Long.valueOf(System.currentTimeMillis() - start))); } - if (packChecksum == null) { + if (packChecksum == null) { packChecksum = idx.getChecksum(); - fileSnapshot.setChecksum( - ObjectId.fromRaw(packChecksum)); + fileSnapshot.setChecksum(ObjectId.fromRaw(packChecksum)); } else if (!Arrays.equals(packChecksum, idx.getChecksum())) { throw new PackMismatchException(MessageFormat @@ -398,6 +421,7 @@ public boolean shouldBeKept() { * @throws IOException * the pack file or the index could not be read. */ + @Nullable ObjectLoader get(WindowCursor curs, AnyObjectId id) throws IOException { final long offset = idx().findOffset(id); @@ -416,6 +440,7 @@ void resolve(Set matches, AbbreviatedObjectId id, int matchLimit) * packs to close */ public static void close(Set packs) { + // TODO(ifrade): purge also nested packs in midx WindowCache.purge(packs); packs.forEach(p -> p.closeIndices()); } @@ -428,7 +453,12 @@ public void close() { closeIndices(); } - private synchronized void closeIndices() { + /** + * Clear the indexes referenced in this pack. + *

+ * Subclasses override this method to clear references to any index they add + */ + protected synchronized void closeIndices() { loadedIdx = Optionally.empty(); reverseIdx = Optionally.empty(); bitmapIdx = Optionally.empty(); @@ -1243,6 +1273,7 @@ long getObjectSize(WindowCursor curs, long pos) } } + @Nullable LocalObjectRepresentation representation(final WindowCursor curs, final AnyObjectId objectId) throws IOException { final long pos = idx().findOffset(objectId); @@ -1316,8 +1347,8 @@ private synchronized PackBitmapIndex memoizeBitmapIndexIfNeeded() throws IOExcep return optional.get(); } try { - PackBitmapIndex idx = PackBitmapIndex.open(bitmapIdxFile, idx(), - getReverseIdx()); + PackBitmapIndex idx = PackBitmapIndex.open(bitmapIdxFile, + getIndex(), getReverseIdx()); // At this point, idx() will have set packChecksum. if (Arrays.equals(packChecksum, idx.getPackChecksum())) { bitmapIdx = optionally(idx); @@ -1342,7 +1373,34 @@ void setBitmapIndexFile(PackFile bitmapIndexFile) { this.bitmapIdxFile = bitmapIndexFile; } - private PackReverseIndex getReverseIdx() throws IOException { + /** + * Return the pack if all its objects are included in the need bitmaps. + * + * @param needBitmaps + * bitmap with needed objects. Modified in this method: If a pack + * is fully included in the bitmap, the pack objects are removed + * from the bitmap. + * @return list of packs fully included in the bitmap + * @throws IOException + * an error reading the bitmap index of this pack + */ + protected List fullyIncludedIn(BitmapIndex.BitmapBuilder needBitmaps) + throws IOException { + PackBitmapIndex bitmapIndex = getBitmapIndex(); + if (needBitmaps.removeAllOrNone(bitmapIndex)) { + return Collections.singletonList(this); + } + return Collections.emptyList(); + } + + /** + * Get the reverse index of this pack + * + * @return a reverse index + * @throws IOException + * an error loading or calculating the reverse index. + */ + protected PackReverseIndex getReverseIdx() throws IOException { Optional optional = reverseIdx.getOptional(); if (optional.isPresent()) { return optional.get(); @@ -1399,7 +1457,16 @@ public String toString() { + ObjectId.fromRaw(packChecksum).name() + "]"; } - private Optionally optionally(T element) { + /** + * Wrap the reference in an Optionally + * + * @param element + * reference + * @return Optionally with the reference inside + * @param + * the type + */ + protected Optionally optionally(T element) { return useStrongRefs ? new Optionally.Hard<>(element) : new Optionally.Soft<>(element); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java index ffbc0737ac7..54100ece164 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java @@ -36,6 +36,8 @@ public class PackBitmapIndexRemapper private final BitSet inflated; private final int[] prevToNewMapping; + private final boolean reuseOldBitmapAsIs; + /** * A PackBitmapIndex that maps the positions in the prevBitmapIndex to the * ones in the newIndex. @@ -65,6 +67,7 @@ private PackBitmapIndexRemapper(PackBitmapIndex newPackIndex) { this.newPackIndex = newPackIndex; this.inflated = null; this.prevToNewMapping = null; + this.reuseOldBitmapAsIs = false; } private PackBitmapIndexRemapper( @@ -73,10 +76,18 @@ private PackBitmapIndexRemapper( this.newPackIndex = newPackIndex; inflated = new BitSet(newPackIndex.getObjectCount()); - prevToNewMapping = new int[oldPackIndex.getObjectCount()]; - for (int pos = 0; pos < prevToNewMapping.length; pos++) - prevToNewMapping[pos] = newPackIndex.findPosition( - oldPackIndex.getObject(pos)); + int[] prevToNewMappingTmp = new int[oldPackIndex.getObjectCount()]; + boolean allPositionsMatch = true; + for (int pos = 0; pos < prevToNewMappingTmp.length; pos++) { + prevToNewMappingTmp[pos] = newPackIndex + .findPosition(oldPackIndex.getObject(pos)); + if (prevToNewMappingTmp[pos] != pos) { + allPositionsMatch = false; + } + } + this.reuseOldBitmapAsIs = allPositionsMatch; + // We do not need it! + this.prevToNewMapping = allPositionsMatch ? null : prevToNewMappingTmp; } @Override @@ -169,10 +180,24 @@ public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) { if (newPackIndex.findPosition(objectId) == -1) return null; + if (reuseOldBitmapAsIs) { + return oldBitmap.getBitmap(); + } + inflated.clear(); - for (IntIterator i = oldBitmap.getBitmapWithoutCaching() - .intIterator(); i.hasNext();) + EWAHCompressedBitmap oldEWAHBitmap = oldBitmap + .getBitmapWithoutCaching(); + if (oldEWAHBitmap.sizeInBits() > oldPackIndex.getObjectCount()) { + throw new IllegalStateException(String.format( + "Bitmap from old index has %d bits but index has only %d objects (new index has %d objects)", + oldEWAHBitmap.sizeInBits(), oldPackIndex.getObjectCount(), + newPackIndex.getObjectCount())); + } + + for (IntIterator i = oldEWAHBitmap.intIterator(); i.hasNext();) { inflated.set(prevToNewMapping[i.next()]); + } + bitmap = inflated.toEWAHCompressedBitmap(); bitmap.trim(); return bitmap; 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 544961b9368..2e06f3ca726 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 @@ -13,6 +13,7 @@ import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; +import static org.eclipse.jgit.lib.Constants.MIDX_FILE; import java.io.File; import java.io.FileNotFoundException; @@ -20,10 +21,12 @@ import java.io.InputStream; import java.nio.file.Files; import java.text.MessageFormat; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; @@ -32,6 +35,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.CorruptObjectException; @@ -45,6 +49,7 @@ 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; @@ -79,6 +84,8 @@ class PackDirectory { private final TrustStat trustPackStat; + private final boolean useMidx; + /** * Initialize a reference to an on-disk 'pack' directory. * @@ -92,6 +99,8 @@ class PackDirectory { this.directory = directory; packList = new AtomicReference<>(NO_PACKS); trustPackStat = config.get(CoreConfig.KEY).getTrustPackStat(); + useMidx = config.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_MULTIPACKINDEX, true); } /** @@ -122,8 +131,7 @@ Collection getPacks() { list = scanPacks(list); } } while (searchPacksAgain(list)); - Pack[] packs = list.packs; - return Collections.unmodifiableCollection(Arrays.asList(packs)); + return Collections.unmodifiableCollection(Arrays.asList(list.packs)); } @Override @@ -136,7 +144,8 @@ public String toString() { * * @param objectId * identity of the object to test for existence of. - * @return {@code true} if the specified object is stored in this PackDirectory. + * @return {@code true} if the specified object is stored in this + * PackDirectory. */ boolean has(AnyObjectId objectId) { return getPack(objectId) != null; @@ -313,45 +322,53 @@ private int checkRescanPackThreshold(int retries, PackMismatchException e) } private void handlePackError(IOException e, Pack p) { - String warnTemplate = null; - String debugTemplate = null; - int transientErrorCount = 0; - String errorTemplate = JGitText.get().exceptionWhileReadingPack; - if ((e instanceof CorruptObjectException) - || (e instanceof PackInvalidException)) { - 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()) { - errorTemplate = JGitText.get().packInaccessible; - transientErrorCount = p.incrementTransientErrorCount(); - } else { - debugTemplate = JGitText.get().packWasDeleted; - remove(p); - } + Throwable cause = e.getCause(); + if (e instanceof FileNotFoundException + || cause instanceof FileNotFoundException) { + handleFileNotFound(e, p); + } else if (e instanceof CorruptObjectException + || e instanceof PackInvalidException) { + handleCorruptPack(e, p); } else if (FileUtils.isStaleFileHandleInCausalChain(e)) { - warnTemplate = JGitText.get().packHandleIsStale; - remove(p); + handleStaleFileHandle(e, p); } else { - transientErrorCount = p.incrementTransientErrorCount(); + handleTransientError(e, p, + JGitText.get().exceptionWhileReadingPack); } - 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); + } + + private void handleFileNotFound(IOException e, Pack p) { + if (p.getPackFile().exists()) { + handleTransientError(e, p, JGitText.get().packInaccessible); } else { - if (doLogExponentialBackoff(transientErrorCount)) { - // Don't remove the pack from the list, as the error may be - // transient. - LOG.error(MessageFormat.format(errorTemplate, - p.getPackFile().getAbsolutePath(), - Integer.valueOf(transientErrorCount)), e); + if (LOG.isDebugEnabled()) { + LOG.debug(MessageFormat.format(JGitText.get().packWasDeleted, + p.getPackFile().getAbsolutePath()), e); } + remove(p); + } + } + + private void handleCorruptPack(IOException e, Pack p) { + LOG.warn(MessageFormat.format(JGitText.get().corruptPack, + p.getPackFile().getAbsolutePath()), e); + // Assume the pack is corrupted, and remove it from the list. + remove(p); + } + + private void handleStaleFileHandle(IOException e, Pack p) { + LOG.warn(MessageFormat.format(JGitText.get().packHandleIsStale, + p.getPackFile().getAbsolutePath()), e); + remove(p); + } + + private void handleTransientError(IOException e, Pack p, + String errorTemplate) { + int transientErrorCount = p.incrementTransientErrorCount(); + if (doLogExponentialBackoff(transientErrorCount)) { + LOG.error(MessageFormat.format(errorTemplate, + p.getPackFile().getAbsolutePath(), + Integer.valueOf(transientErrorCount)), e); } } @@ -371,7 +388,8 @@ boolean searchPacksAgain(PackList old) { case AFTER_OPEN: try (InputStream stream = Files .newInputStream(directory.toPath())) { - // open the pack directory to refresh attributes (on some NFS clients) + // open the pack directory to refresh attributes (on some NFS + // clients) } catch (IOException e) { // ignore } @@ -462,6 +480,7 @@ private PackList scanPacks(PackList original) { private PackList scanPacksImpl(PackList old) { final Map forReuse = reuseMap(old); final FileSnapshot snapshot = FileSnapshot.save(directory); + Map> packFilesByExtById = getPackFilesByExtById(); List list = new ArrayList<>(packFilesByExtById.size()); boolean foundNew = false; @@ -488,10 +507,32 @@ private PackList scanPacksImpl(PackList old) { continue; } - list.add(new Pack(config, packFile, packFilesByExt.get(BITMAP_INDEX))); + list.add(new Pack(config, packFile, + packFilesByExt.get(BITMAP_INDEX))); foundNew = true; } + PackMidx theMidx = null; + File midx = new File(directory, MIDX_FILE); + if (useMidx && midx.exists()) { + Pack oldMidx = forReuse.get(midx.getName()); + if (oldMidx != null + && !oldMidx.getFileSnapshot().isModified(midx)) { + // Reuse the previous instance + forReuse.remove(midx.getName()); + theMidx = (PackMidx) oldMidx; + } else { + try { + theMidx = new PackMidx(config, midx, list); + foundNew = true; + } catch (IOException e) { + // pass + LOG.warn(MessageFormat.format(JGitText.get().cannotOpenMidx, + midx.getAbsolutePath(), e.getMessage())); + } + } + } + // If we did not discover any new files, the modification time was not // changed, and we did not remove any files, then the set of files is // the same as the set we were given. Instead of building a new object @@ -508,6 +549,22 @@ private PackList scanPacksImpl(PackList old) { return new PackList(snapshot, NO_PACKS.packs); } + if (useMidx && theMidx != null) { + // Replace the covered packs with the midx in the list + Set coveredPackNames = theMidx.getCoveredPacks().stream() + .map(p -> p.getPackName()) + .collect(Collectors.toUnmodifiableSet()); + int packsBefore = list.size(); + list = list.stream() + .filter(p -> !coveredPackNames.contains(p.getPackName())) + .collect(Collectors.toCollection(ArrayList::new)); + int packsAfter = list.size(); + LOG.debug(String.format( + "Mangling packlist: midx replaces %d packs (list went from %d to %d packs)", //$NON-NLS-1$ + coveredPackNames.size(), packsBefore, packsAfter)); + list.add(theMidx); + } + final Pack[] r = list.toArray(new Pack[0]); Arrays.sort(r, Pack.SORT); return new PackList(snapshot, r); @@ -515,7 +572,9 @@ private PackList scanPacksImpl(PackList old) { private static Map reuseMap(PackList old) { final Map forReuse = new HashMap<>(); - for (Pack p : old.packs) { + Deque queue = new ArrayDeque<>(List.of(old.packs)); + while (!queue.isEmpty()) { + Pack p = queue.removeFirst(); if (p.invalid()) { // The pack instance is corrupted, and cannot be safely used // again. Do not include it in our reuse map. @@ -524,6 +583,8 @@ private static Map reuseMap(PackList old) { continue; } + queue.addAll(p.getCoveredPacks()); + final Pack prior = forReuse.put(p.getPackFile().getName(), p); if (prior != null) { // This should never occur. It should be impossible for us diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackMidx.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackMidx.java new file mode 100644 index 00000000000..7bf187fe6d1 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackMidx.java @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2026, 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.file; + +import static java.util.stream.Collectors.toMap; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.zip.DataFormatException; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.errors.LargeObjectException; +import org.eclipse.jgit.errors.PackInvalidException; +import org.eclipse.jgit.internal.storage.midx.MidxMetadataReader; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.pack.PackOutputStream; +import org.eclipse.jgit.internal.util.Optionally; +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BitmapIndex; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; + +/** + * A pack that uses internally a midx + *

+ * This pack answers what it can directly from the midx (e.g. hasObject) and + * sends to the right pack other calls (e.g. reading the actual object). + */ +public class PackMidx extends Pack { + private final List packsInIdOrder; + + private final OffsetCalculator offsetCalculator; + + private Optionally midx = Optionally.empty(); + + private volatile PackIndex idx; + + private volatile PackReverseIndex ridx; + + // TODO(ifrade): Encapsulate invalid/invalidatingCause in Pack to reuse here + private IOException invalidatingCause; + + /** + * Construct a reader for existing, pre-indexed packfiles. + * + * @param cfg + * configuration this directory consults for write settings. + * @param midxFile + * path of the .midx file holding the data. + * @param knownPacks + * packs in the repo to find the packs covered by this midx + * @throws IOException + * an error reading any of the files involved + */ + public PackMidx(Config cfg, File midxFile, List knownPacks) + throws IOException { + super(cfg, midxFile, null); + MidxMetadataReader.MidxMetadata midxMeta = MidxMetadataReader + .read(midxFile); + // Maybe we could load only the packnames chunk at this point + setPackChecksum(midxMeta.checksum()); + String[] packNames = midxMeta.packNames().toArray(new String[0]); + + Map knownPacksByName = knownPacks.stream() + .collect(toMap( + p -> p.getPackFile().create(PackExt.INDEX).getName(), + Function.identity())); + packsInIdOrder = Arrays.stream(packNames).map(knownPacksByName::get) + .filter(Objects::nonNull) + .toList(); + if (packsInIdOrder.size() != packNames.length) { + throw new IOException("Midx refers to packs not in the pack list"); //$NON-NLS-1$ + } + offsetCalculator = new OffsetCalculator(packsInIdOrder.stream() + .mapToLong(p -> p.getPackFile().length()).toArray()); + + ObjectId checksumHex = ObjectId.fromRaw(midxMeta.checksum()); + File midxBitmaps = new File(midxFile.getParentFile(), String.format( + "%s-%s.bitmap", Constants.MIDX_FILE, checksumHex.name())); + if (midxBitmaps.exists()) { + setBitmapIndexFile(new PackFile(midxBitmaps)); + } + } + + /** + * Return the packs covered by this midx (in midx order) + * + * @return packs covered by this midx + */ + @Override + public List getCoveredPacks() { + return packsInIdOrder; + } + + @Override + protected List fullyIncludedIn(BitmapIndex.BitmapBuilder needBitmaps) + throws IOException { + PackBitmapIndex bitmapIndex = getBitmapIndex(); + if (needBitmaps.removeAllOrNone(bitmapIndex)) { + return getCoveredPacks(); + } + return Collections.emptyList(); + } + + @Override + public PackIndex getIndex() { + if (idx == null) { + synchronized (this) { + if (idx == null) { + try { + idx = new MidxPackIndex(getMidx(), offsetCalculator); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + } + return idx; + } + + @Override + public PackReverseIndex getReverseIdx() { + if (ridx == null) { + synchronized (this) { + if (ridx == null) { + try { + ridx = new MidxPackReverseIndex(getMidx(), + offsetCalculator); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + } + return ridx; + } + + @Override + public boolean hasObjectSizeIndex() throws IOException { + return false; + } + + @Override + public long getObjectSizeIndexCount() { + throw new UnsupportedOperationException(); + } + + @Override + public long getIndexedObjectSize(AnyObjectId id) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasObject(AnyObjectId id) throws IOException { + return getMidx().hasObject(id); + } + + @Override + public boolean shouldBeKept() { + return false; + } + + @Override + @Nullable + ObjectLoader get(WindowCursor curs, AnyObjectId id) throws IOException { + MultiPackIndex.PackOffset packOffset = getMidx().find(id); + if (packOffset == null) { + return null; + } + return packsInIdOrder.get(packOffset.getPackId()).get(curs, id); + } + + @Override + void resolve(Set matches, AbbreviatedObjectId id, int matchLimit) + throws IOException { + getMidx().resolve(matches, id, matchLimit); + } + + @Override + protected synchronized void closeIndices() { + for (Pack p : getCoveredPacks()) { + p.closeIndices(); + } + midx = Optionally.empty(); + super.closeIndices(); + } + + @Override + public Iterator iterator() { + return getIndex().iterator(); + } + + @Override + long getObjectCount() throws IOException { + return getMidx().getObjectCount(); + } + + @Override + ObjectId findObjectForOffset(long offset) throws IOException { + MultiPackIndex.PackOffset decode = offsetCalculator.decode(offset); + if (decode == null) { + return null; + } + MultiPackIndex theMidx = getMidx(); + int bitmapPosition = theMidx.findBitmapPosition(decode); + if (bitmapPosition < 0) { + throw new IllegalStateException( + "Object in midx without ridx position"); + } + + return theMidx.getObjectAtBitmapPosition(bitmapPosition); + } + + @Override + ObjectId getPackChecksum() { + try { + return ObjectId.fromRaw(getMidx().getChecksum()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + void copyPackAsIs(PackOutputStream out, WindowCursor curs) + throws IOException { + for (Pack p : packsInIdOrder) { + p.copyPackAsIs(out, curs); + } + } + + @Override + boolean beginWindowCache() throws IOException { + boolean startedWindow = false; + for (Pack p : packsInIdOrder) { + startedWindow |= p.beginWindowCache(); + } + return startedWindow; + } + + @Override + boolean endWindowCache() { + boolean lastWindow = false; + for (Pack p : packsInIdOrder) { + lastWindow |= p.endWindowCache(); + } + return lastWindow; + } + + @Override + ByteArrayWindow read(long pos, int size) throws IOException { + MultiPackIndex.PackOffset po = offsetCalculator.decode(pos); + if (po == null) { + throw new IllegalArgumentException("Invalid offset " + pos); + } + return packsInIdOrder.get(po.getPackId()).read(po.getOffset(), size); + } + + @Override + ByteWindow mmap(long pos, int size) throws IOException { + MultiPackIndex.PackOffset po = offsetCalculator.decode(pos); + if (po == null) { + throw new IllegalArgumentException("Invalid offset " + pos); + } + return packsInIdOrder.get(po.getPackId()).mmap(po.getOffset(), size); + } + + @Override + ObjectLoader load(WindowCursor curs, long pos) + throws IOException, LargeObjectException { + MultiPackIndex.PackOffset po = offsetCalculator.decode(pos); + if (po == null) { + throw new IllegalArgumentException("Invalid offset " + pos); + } + return packsInIdOrder.get(po.getPackId()).load(curs, po.getOffset()); + } + + @Override + byte[] getDeltaHeader(WindowCursor wc, long pos) + throws IOException, DataFormatException { + MultiPackIndex.PackOffset po = offsetCalculator.decode(pos); + if (po == null) { + throw new IllegalArgumentException("Invalid offset " + pos); + } + return packsInIdOrder.get(po.getPackId()).getDeltaHeader(wc, + po.getOffset()); + } + + @Override + int getObjectType(WindowCursor curs, long pos) throws IOException { + MultiPackIndex.PackOffset po = offsetCalculator.decode(pos); + if (po == null) { + throw new IllegalArgumentException("Invalid offset " + pos); + } + return packsInIdOrder.get(po.getPackId()).getObjectType(curs, + po.getOffset()); + } + + @Override + long getObjectSize(WindowCursor curs, AnyObjectId id) throws IOException { + MultiPackIndex.PackOffset po = getMidx().find(id); + if (po == null) { + return -1; + } + return packsInIdOrder.get(po.getPackId()).getObjectSize(curs, + po.getOffset()); + } + + @Override + long getObjectSize(WindowCursor curs, long pos) throws IOException { + MultiPackIndex.PackOffset po = offsetCalculator.decode(pos); + if (po == null) { + throw new IllegalArgumentException("Invalid offset " + pos); + } + return packsInIdOrder.get(po.getPackId()).getObjectSize(curs, + po.getOffset()); + } + + @Override + @Nullable + LocalObjectRepresentation representation(WindowCursor curs, + AnyObjectId objectId) throws IOException { + MultiPackIndex.PackOffset po = getMidx().find(objectId); + if (po == null) { + return null; + } + return packsInIdOrder.get(po.getPackId()).representation(curs, + objectId); + } + + private MultiPackIndex getMidx() throws IOException { + Optional optional = midx.getOptional(); + if (optional.isPresent()) { + return optional.get(); + } + return memoizeMidxIfNeeded(); + } + + private synchronized MultiPackIndex memoizeMidxIfNeeded() + throws IOException { + if (invalid()) { + throw new PackInvalidException(getPackFile(), invalidatingCause); + } + Optional optional = midx.getOptional(); + if (optional.isPresent()) { + return optional.get(); + } + + try { + MultiPackIndex loadedMidx = MultiPackIndexLoader + .open(getPackFile()); + midx = optionally(loadedMidx); + return loadedMidx; + } catch (IOException e) { + setInvalid(); + invalidatingCause = e; + throw e; + } + } + + private static class OffsetCalculator { + private final MultiPackIndex.PackOffset mutablePo = new MultiPackIndex.PackOffset(); + + private final long[] accSizes; + + OffsetCalculator(long[] packSizes) { + accSizes = new long[packSizes.length]; + accSizes[0] = 0; + for (int i = 1; i < packSizes.length; i++) { + accSizes[i] = accSizes[i - 1] + packSizes[i - 1]; + } + } + + long encode(MultiPackIndex.PackOffset po) { + if (po == null) { + return -1; + } + return accSizes[po.getPackId()] + po.getOffset(); + } + + long encode(int packId, long offset) { + return accSizes[packId] + offset; + } + + @Nullable + MultiPackIndex.PackOffset decode(long totalOffset) { + if (totalOffset < 0) { + return null; + } + + for (int i = accSizes.length - 1; i >= 0; i--) { + if (totalOffset >= accSizes[i]) { + return mutablePo.setValues(i, totalOffset - accSizes[i]); + } + } + return null; + } + } + + private static class MidxPackIndex implements PackIndex { + + private final MultiPackIndex midx; + + private final OffsetCalculator offsetCalculator; + + MidxPackIndex(MultiPackIndex midx, OffsetCalculator offsetCalculator) { + this.midx = midx; + this.offsetCalculator = offsetCalculator; + } + + @Override + public Iterator iterator() { + MultiPackIndex.MidxIterator it = midx.iterator(); + return new Iterator<>() { + + private final MutableEntry me = new MutableEntry(); + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public MutableEntry next() { + MultiPackIndex.MutableEntry entry = it.next(); + me.idBuffer.fromObjectId(entry.getObjectId()); + me.offset = offsetCalculator.encode(entry.getPackId(), + entry.getOffset()); + return me; + } + }; + } + + @Override + public long getObjectCount() { + return midx.getObjectCount(); + } + + @Override + public long getOffset64Count() { + return 0; + } + + @Override + public ObjectId getObjectId(long nthPosition) { + if (nthPosition < 0) { + throw new IllegalArgumentException(); + } + return midx.getObjectAt((int) nthPosition); + } + + @Override + public long getOffset(long nthPosition) { + ObjectId objectAt = midx.getObjectAt((int) nthPosition); + MultiPackIndex.PackOffset packOffset = midx.find(objectAt); + return offsetCalculator.encode(packOffset); + } + + @Override + public long findOffset(AnyObjectId objId) { + MultiPackIndex.PackOffset packOffset = midx.find(objId); + return offsetCalculator.encode(packOffset); + } + + @Override + public int findPosition(AnyObjectId objId) { + return midx.findPosition(objId); + } + + @Override + public long findCRC32(AnyObjectId objId) + throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasCRC32Support() { + return false; + } + + @Override + public void resolve(Set matches, AbbreviatedObjectId id, + int matchLimit) { + midx.resolve(matches, id, matchLimit); + } + + @Override + public byte[] getChecksum() { + return midx.getChecksum(); + } + } + + private static final class MidxPackReverseIndex + implements PackReverseIndex { + + private final MultiPackIndex midx; + + private final OffsetCalculator offsetCalculator; + + MidxPackReverseIndex(MultiPackIndex midx, + OffsetCalculator offsetCalculator) { + this.midx = midx; + this.offsetCalculator = offsetCalculator; + } + + @Override + public void verifyPackChecksum(String packFilePath) { + } + + @Override + public ObjectId findObject(long offset) { + MultiPackIndex.PackOffset po = offsetCalculator.decode(offset); + int revPos = midx.findBitmapPosition(po); + return midx.getObjectAtBitmapPosition(revPos); + } + + @Override + public long findNextOffset(long offset, long maxOffset) { + throw new UnsupportedOperationException(); + } + + @Override + public int findPosition(long offset) { + MultiPackIndex.PackOffset po = offsetCalculator.decode(offset); + return midx.findBitmapPosition(po); + } + + @Override + public ObjectId findObjectByPosition(int nthPosition) { + return midx.getObjectAtBitmapPosition(nthPosition); + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java index 4b5566e113a..f33fe0b3b87 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java @@ -178,7 +178,7 @@ public void execute(RevWalk walk, ProgressMonitor monitor, return; } refdb.commitPackedRefs(packedRefsLock, newRefs, oldPackedList, - true); + true, oldPackedList.traits()); } catch (LockFailedException e) { lockFailure(pending.get(0), pending); return; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java index 9fa3ff3d9fa..a9211fe9cfc 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 @@ -46,6 +46,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -71,12 +72,13 @@ import org.eclipse.jgit.lib.CoreConfig.TrustStat; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.PackedRefsTrait; +import org.eclipse.jgit.lib.PackedRefsWriter; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefComparator; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefUpdate; -import org.eclipse.jgit.lib.RefWriter; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.SymbolicRef; @@ -118,12 +120,6 @@ public class RefDirectory extends RefDatabase { /** Magic string denoting the header of a packed-refs file. */ public static final String PACKED_REFS_HEADER = "# pack-refs with:"; //$NON-NLS-1$ - /** If in the header, denotes the file has peeled data. */ - public static final String PACKED_REFS_PEELED = " peeled"; //$NON-NLS-1$ - - /** If in the header, denotes the file has sorted data. */ - public static final String PACKED_REFS_SORTED = " sorted"; //$NON-NLS-1$ - @SuppressWarnings("boxing") private static final List RETRY_SLEEP_MS = Collections.unmodifiableList(Arrays.asList(0, 100, 200, 400, 800, 1600)); @@ -155,8 +151,7 @@ public class RefDirectory extends RefDatabase { /** Immutable sorted list of packed references. */ final AtomicReference packedRefs = new AtomicReference<>(); - private final AtomicReference packedRefsRefresher = - new AtomicReference<>(); + private final AtomicReference packedRefsRefresher; /** * Lock for coordinating operations within a single process that may contend @@ -205,6 +200,7 @@ public class RefDirectory extends RefDatabase { looseRefs.set(refDb.looseRefs.get()); packedRefs.set(refDb.packedRefs.get()); coreConfig = refDb.coreConfig; + packedRefsRefresher = refDb.packedRefsRefresher; inProcessPackedRefsLock = refDb.inProcessPackedRefsLock; } @@ -221,6 +217,7 @@ public class RefDirectory extends RefDatabase { looseRefs.set(RefList. emptyList()); packedRefs.set(NO_PACKED_REFS); coreConfig = db.getConfig().get(CoreConfig.KEY); + packedRefsRefresher = new AtomicReference<>(); inProcessPackedRefsLock = new ReentrantLock(true); } @@ -726,7 +723,8 @@ void delete(RefDirectoryUpdate update) throws IOException { packed = getLockedPackedRefs(lck); int idx = packed.find(name); if (0 <= idx) { - commitPackedRefs(lck, packed.remove(idx), packed, true); + commitPackedRefs(lck, packed.remove(idx), packed, true, + packed.traits); } } @@ -743,7 +741,11 @@ void delete(RefDirectoryUpdate update) throws IOException { int levels = levelsIn(name) - 2; delete(logFor(name), levels); if (dst.getStorage().isLoose()) { - deleteAndUnlock(fileFor(name), levels, update); + File refFile = fileFor(name); + ObjectId refObjectId = dst.getObjectId(); + deleteAndUnlock(refFile, levels, update); + LOG.debug(JGitText.get().deleteLooseRef, + refFile, refObjectId); } } finally { lck.unlock(); @@ -827,7 +829,14 @@ private void pack(Collection refs, } // The new content for packed-refs is collected. Persist it. - commitPackedRefs(lck, newPacked, oldPacked,false); + commitPackedRefs(lck, newPacked, oldPacked, false, + // If all packed-refs content is new, start with all + // traits. + oldPacked.isEmpty() + ? EnumSet.of(PackedRefsTrait.SORTED, + PackedRefsTrait.PEELED, + PackedRefsTrait.FULLY_PEELED) + : oldPacked.traits); // Now delete the loose refs which are now packed for (String refName : refs) { @@ -869,6 +878,7 @@ private void pack(Collection refs, } while (!looseRefs.compareAndSet(curLoose, newLoose)); int levels = levelsIn(refName) - 2; deleteAndUnlock(refFile, levels, rLck); + LOG.debug(JGitText.get().deleteLooseRef, refFile, clr_oid); } } finally { if (shouldUnlock) { @@ -1066,9 +1076,7 @@ private PackedRefList readPackedRefs() throws IOException { new DigestInputStream( new FileInputStream(f), digest), UTF_8))) { - return new NonEmptyPackedRefList(parsePackedRefs(br), - snapshot, - ObjectId.fromRaw(digest.digest())); + return parsePackedRefs(br, snapshot, digest); } }); return result != null ? result : NO_PACKED_REFS; @@ -1087,19 +1095,23 @@ void compareAndSetPackedRefs(PackedRefList curList, PackedRefList newList) { } } - private RefList parsePackedRefs(BufferedReader br) - throws IOException { + private NonEmptyPackedRefList parsePackedRefs(BufferedReader br, + FileSnapshot snapshot, MessageDigest digest) throws IOException { RefList.Builder all = new RefList.Builder<>(); Ref last = null; boolean peeled = false; + boolean fullyPeeled = false; boolean needSort = false; + boolean isSorted = false; String p; while ((p = br.readLine()) != null) { if (p.charAt(0) == '#') { if (p.startsWith(PACKED_REFS_HEADER)) { p = p.substring(PACKED_REFS_HEADER.length()); - peeled = p.contains(PACKED_REFS_PEELED); + peeled = p.contains(PackedRefsTrait.PEELED.value()); + isSorted = p.contains(PackedRefsTrait.SORTED.value()); + fullyPeeled = p.contains(PackedRefsTrait.FULLY_PEELED.value()); } continue; } @@ -1124,19 +1136,32 @@ private RefList parsePackedRefs(BufferedReader br) ObjectId id = ObjectId.fromString(p.substring(0, sp)); String name = copy(p, sp + 1, p.length()); ObjectIdRef cur; - if (peeled) + if (fullyPeeled || (peeled && name.startsWith(R_TAGS))) { cur = new ObjectIdRef.PeeledNonTag(PACKED, name, id); - else + } else { cur = new ObjectIdRef.Unpeeled(PACKED, name, id); - if (last != null && RefComparator.compareTo(last, cur) > 0) + } + if (!isSorted && last != null && RefComparator.compareTo(last, cur) > 0) { needSort = true; + } all.add(cur); last = cur; } if (needSort) all.sort(); - return all.toRefList(); + + EnumSet traits = EnumSet.noneOf(PackedRefsTrait.class); + traits.add(PackedRefsTrait.SORTED); + if (fullyPeeled || peeled) { + traits.add(PackedRefsTrait.PEELED); + } + if (fullyPeeled) { + traits.add(PackedRefsTrait.FULLY_PEELED); + } + + return new NonEmptyPackedRefList(all.toRefList(), snapshot, + ObjectId.fromRaw(digest.digest()), traits); } private static String copy(String src, int off, int end) { @@ -1145,10 +1170,10 @@ private static String copy(String src, int off, int end) { return new StringBuilder(end - off).append(src, off, end).toString(); } - void commitPackedRefs(final LockFile lck, final RefList refs, - final PackedRefList oldPackedList, boolean changed) - throws IOException { - new RefWriter(refs) { + void commitPackedRefs(final LockFile lck, final RefList refsList, + final PackedRefList oldPackedList, boolean changed, + EnumSet traits) throws IOException { + new PackedRefsWriter(refsList.asList(), traits, this) { @Override protected void writeFile(String name, byte[] content) throws IOException { @@ -1173,7 +1198,8 @@ protected void writeFile(String name, byte[] content) byte[] digest = Constants.newMessageDigest().digest(content); PackedRefList newPackedList = new NonEmptyPackedRefList( - refs, lck.getCommitSnapshot(), ObjectId.fromRaw(digest)); + asRefList(), lck.getCommitSnapshot(), + ObjectId.fromRaw(digest), traits); packedRefs.compareAndSet(oldPackedList, newPackedList); if (changed) { modCnt.incrementAndGet(); @@ -1320,6 +1346,7 @@ class LooseItems { * path of a loose ref relative to the repository root */ void refreshPathToLooseRef(Path refPath) { + boolean failed = false; for (int i = 1; i < refPath.getNameCount(); i++) { File dir = fileFor(refPath.subpath(0, i).toString()); // Use Files.newInputStream(Path) as it is consistent with other @@ -1328,7 +1355,16 @@ void refreshPathToLooseRef(Path refPath) { try (InputStream stream = Files.newInputStream(dir.toPath())) { // open the dir to refresh attributes (on some NFS clients) } catch (IOException e) { - break; // loose ref may not exist + failed = true; + break; // directory may not exist + } + } + if (!failed) { + try (InputStream stream = Files.newInputStream(refPath)) { + // open the loose ref to refresh attributes (on some NFS + // clients) + } catch (IOException e) { + // loose ref may not exist } } } @@ -1527,19 +1563,27 @@ static void sleep(long ms) throws InterruptedIOException { static class PackedRefList extends RefList { private final ObjectId id; + private final EnumSet traits; PackedRefList() { - this(RefList.emptyList(), ObjectId.zeroId()); + this(RefList.emptyList(), ObjectId.zeroId(), + EnumSet.noneOf(PackedRefsTrait.class)); } - protected PackedRefList(RefList src, ObjectId id) { + protected PackedRefList(RefList src, ObjectId id, + EnumSet traits) { super(src); this.id = id; + this.traits = traits.clone(); } public boolean shouldRefresh() throws IOException { return true; } + + public EnumSet traits() { + return traits.clone(); + } } private static final PackedRefList NO_PACKED_REFS = new PackedRefList(); @@ -1547,8 +1591,9 @@ public boolean shouldRefresh() throws IOException { private class NonEmptyPackedRefList extends PackedRefList { private final FileSnapshot snapshot; - private NonEmptyPackedRefList(RefList src, FileSnapshot s, ObjectId id) { - super(src, id); + private NonEmptyPackedRefList(RefList src, FileSnapshot s, + ObjectId id, EnumSet traits) { + super(src, id, traits); snapshot = s; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java index 6870d7686eb..9fb7ffc9860 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java @@ -57,33 +57,21 @@ public class ReflogEntryImpl implements Serializable, ReflogEntry { } } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getOldId() - */ @Override public ObjectId getOldId() { return oldId; } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getNewId() - */ @Override public ObjectId getNewId() { return newId; } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getWho() - */ @Override public PersonIdent getWho() { return who; } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getComment() - */ @Override public String getComment() { return comment; @@ -96,9 +84,6 @@ public String toString() { + ", " + getComment() + "]"; } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#parseCheckout() - */ @Override public CheckoutEntry parseCheckout() { if (getComment().startsWith(CheckoutEntryImpl.CHECKOUT_MOVING_FROM)) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java index f1888eb90f7..98bc108cf62 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java @@ -44,25 +44,16 @@ class ReflogReaderImpl implements ReflogReader { logName = new File(logBaseDir, Constants.L_LOGS + refname); } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getLastEntry() - */ @Override public ReflogEntry getLastEntry() throws IOException { return getReverseEntry(0); } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntries() - */ @Override public List getReverseEntries() throws IOException { return getReverseEntries(Integer.MAX_VALUE); } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntry(int) - */ @Override public ReflogEntry getReverseEntry(int number) throws IOException { if (number < 0) @@ -89,9 +80,6 @@ public ReflogEntry getReverseEntry(int number) throws IOException { return null; } - /* (non-Javadoc) - * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntries(int) - */ @Override public List getReverseEntries(int max) throws IOException { final byte[] log; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java index 33459ef18de..cf485a47e29 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java @@ -12,6 +12,7 @@ package org.eclipse.jgit.internal.storage.file; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -26,6 +27,7 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.internal.storage.pack.CachedPack; import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs; import org.eclipse.jgit.internal.storage.pack.ObjectToPack; @@ -35,7 +37,6 @@ import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.BitmapIndex; import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; -import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.InflaterCache; @@ -115,13 +116,15 @@ public Optional getCommitGraph() { @Override public Collection getCachedPacksAndUpdate( BitmapBuilder needBitmap) throws IOException { + List toUseAsIs = new ArrayList<>(); for (Pack pack : db.getPacks()) { - PackBitmapIndex index = pack.getBitmapIndex(); - if (needBitmap.removeAllOrNone(index)) - return Collections. singletonList( - new LocalCachedPack(Collections.singletonList(pack))); + List packs = pack.fullyIncludedIn(needBitmap); + if (packs.isEmpty()) { + continue; + } + toUseAsIs.add(new LocalCachedPack(packs)); } - return Collections.emptyList(); + return toUseAsIs; } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/memory/TernarySearchTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/memory/TernarySearchTree.java index 72434dbffeb..bc2c028189c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/memory/TernarySearchTree.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/memory/TernarySearchTree.java @@ -43,7 +43,7 @@ * type of values in this tree * @since 6.5 */ -public final class TernarySearchTree { +public class TernarySearchTree { private static final char WILDCARD = '?'; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxIterators.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxIterators.java index 30dc612e451..c30b9b8c989 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxIterators.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxIterators.java @@ -29,14 +29,14 @@ public final class MidxIterators { * * @param packName * pack name this iterator is going over - * @param idxIt - * iterator over a PackIndex + * @param idx + * a PackIndex * @return a midx iterator that returns the objects of the pack index in the * original iterator order */ public static MidxIterator fromPackIndexIterator(String packName, - Iterator idxIt) { - return new MidxIteratorOverPackIndex(packName, idxIt); + PackIndex idx) { + return new MidxIteratorOverPackIndex(packName, idx); } /** @@ -80,17 +80,19 @@ private static class MidxIteratorOverPackIndex implements MidxIterator { private final List packNames; - private final Iterator idxIt; + private final PackIndex idx; + + private Iterator idxIt; private boolean peeked; - private final MutableEntry entry; + private final MutableEntry entry = new MutableEntry(); MidxIteratorOverPackIndex(String packName, - Iterator idxIt) { + PackIndex idx) { this.packNames = List.of(packName); - this.idxIt = idxIt; - this.entry = new MutableEntry(); + this.idx = idx; + this.idxIt = idx.iterator(); } @Override @@ -132,6 +134,13 @@ private void readNext() { idx.copyOidTo(entry.oid); entry.packOffset.setValues(0, idx.getOffset()); } + + @Override + public void reset() { + this.idxIt = idx.iterator(); + this.entry.clear(); + peeked = false; + } } private static class JoinMidxIterator implements MidxIterator { @@ -186,6 +195,7 @@ private MutableEntry shiftPackId(MutableEntry entry, int shift) { private int best() { int winnerPos = -1; + int winnerPackShift = 0; MidxIterator winner = null; for (int index = 0; index < indexIterators.size(); index++) { MidxIterator current = indexIterators.get(index); @@ -193,9 +203,11 @@ private int best() { continue; } if (winner == null - || current.peek().compareTo(winner.peek()) < 0) { + || compareEntries(current.peek(), packCountAgg[index], + winner.peek(), winnerPackShift) < 0) { winner = current; winnerPos = index; + winnerPackShift = packCountAgg[winnerPos]; } } @@ -205,6 +217,23 @@ private int best() { return winnerPos; } + + private static int compareEntries(MutableEntry a, int aPackShift, + MutableEntry b, int bPackShift) { + int cmp = a.oid.compareTo(b.oid); + if (cmp != 0) { + return cmp; + } + + return Integer.compare(a.getPackId() + aPackShift, + b.getPackId() + bPackShift); + } + + @Override + public void reset() { + indexIterators.stream().forEach(MidxIterator::reset); + local.clear(); + } } private static class DedupMidxIterator implements MidxIterator { @@ -264,5 +293,12 @@ private void readNext() { } } } + + @Override + public void reset() { + lastOid.clear(); + src.reset(); + readNext(); + } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxMetadataReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxMetadataReader.java new file mode 100644 index 00000000000..26c0bb47eb1 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxMetadataReader.java @@ -0,0 +1,266 @@ +/* + * 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_PACKNAMES; +import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_SIGNATURE; + +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.Base64; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.NB; +import org.eclipse.jgit.util.io.SilentFileInputStream; + +/** + * Read only basic metadata from the midx without loading the whole file in + * memory. + *

+ * In some cases we need only a bit of information from the midx and we do not + * need it yet fully loaded in memory. For example: + *

    + *
  • We need the checksum of the previous midx to delete its bitmaps
  • + *
  • When opening the repo, we need the names of packs referenced by the midx + * to check they exist
  • + *
+ */ +public class MidxMetadataReader { + + private MidxMetadataReader() { + } + + /** + * Metadata useful before loading the full midx + * + * @param packNames + * list of packs in this midx (in midx order). + * @param checksumB64 + * checksum of the midx, encoded in Base64 + */ + public record MidxMetadata(List packNames, String checksumB64) { + /** + * Return the checksum as byte[] + * + * @return checksum in byte[] format + */ + public byte[] checksum() { + return Base64.decode(checksumB64); + } + } + + /** + * Open an existing MultiPackIndex file and read its metadata + * + * @param midxFile + * existing multi-pack-index to read. + * @return the metadata + * @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 MidxMetadata read(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 metadata from an existing MultiPackIndex from a buffered stream. + * + * @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 the metadata + * @throws MultiPackIndexFormatException + * the MultiPackIndex file's format is different from we + * expected. + * @throws java.io.IOException + * the stream cannot be read. + */ + public static MidxMetadata 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, Integer.valueOf(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); + + ChunkIndex chunkIndex = ChunkIndex.read(fd, chunkCount); + int currentPos = hdr.length + chunkIndex.getBytesRead(); + long packNamesStart = chunkIndex.getStartOffset(MIDX_CHUNKID_PACKNAMES); + long packNamesEnd = chunkIndex.getEndOffset(MIDX_CHUNKID_PACKNAMES); + + IO.skipFully(fd, packNamesStart - currentPos); + byte[] packNamesBuffer = new byte[(int) (packNamesEnd + - packNamesStart)]; + IO.readFully(fd, packNamesBuffer); + List packNames = List + .of(new String(packNamesBuffer, UTF_8).split("\u0000")); + if (packCount != packNames.size()) { + throw new MultiPackIndexFormatException(MessageFormat.format( + JGitText.get().multiPackIndexPackCountMismatch, packCount, + packNames.size())); + } + + // We should be at packNamesEnd + long endLastChunk = chunkIndex.getLastOffset(); + IO.skipFully(fd, endLastChunk - packNamesEnd); + byte[] checksum = new byte[20]; + IO.readFully(fd, checksum, 0, 20); + + return new MidxMetadata(packNames, Base64.encodeBytes(checksum)); + } + + private static final class ChunkIndex { + + private final List chunks; + + private final int byteSize; + + static ChunkIndex read(InputStream fd, int chunkCount) + throws IOException { + byte[] lookupBuffer = new byte[CHUNK_LOOKUP_WIDTH + * (chunkCount + 1)]; + + IO.readFully(fd, lookupBuffer, 0, lookupBuffer.length); + + List 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 new ChunkIndex(chunks, lookupBuffer.length); + } + + private ChunkIndex(List chunks, int bytesRead) { + this.chunks = chunks; + this.byteSize = bytesRead; + } + + /** + * Bytes read from the stream while reading the chunks + * + * @return number of bytes consumed from the stream + */ + int getBytesRead() { + return byteSize; + } + + long getStartOffset(int chunkId) { + for (ChunkSegment c : chunks) { + if (c.id() == chunkId) { + return c.offset(); + } + } + throw new IllegalArgumentException("Asking for unknown chunk"); //$NON-NLS-1$ + } + + long getEndOffset(int chunkId) { + int pos = -1; + for (int i = 0; i < chunks.size(); i++) { + if (chunks.get(i).id() == chunkId) { + pos = i; + break; + } + } + if (pos == -1) { + throw new IllegalArgumentException("Asking for unknown chunk"); //$NON-NLS-1$ + } + + return chunks.get(pos + 1).offset(); + } + + long getLastOffset() { + return chunks.get(chunks.size() - 1).offset(); + } + } + + private record ChunkSegment(int id, long offset) { + } + + /** + * Thrown if a MultiPackIndex doesn't have the expected file format + */ + 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/MultiPackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndex.java index 1721cb69ca0..b209aa96a6c 100644 --- 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 @@ -162,6 +162,11 @@ interface MidxIterator extends Iterator { * @return pack names */ List getPackNames(); + + /** + * Restart the iteration from the beginning + */ + void reset(); } /** @@ -235,21 +240,11 @@ public String toString() { *

* Mutable so the iterator can reuse the instance for performance. */ - class MutableEntry implements Comparable { + class MutableEntry { protected final MutableObjectId oid = new MutableObjectId(); protected final PackOffset packOffset = new PackOffset(); - @Override - public int compareTo(MutableEntry mutableEntry) { - int cmp = oid.compareTo(mutableEntry.oid); - if (cmp != 0) { - return cmp; - } - - return packOffset.getPackId() - mutableEntry.packOffset.getPackId(); - } - /** * Copy data from other into this instance, adding the shift to the * packId @@ -278,6 +273,11 @@ public long getOffset() { return packOffset.getOffset(); } + public void clear() { + oid.clear(); + packOffset.setValues(0, 0); + } + @Override public String toString() { return String.format("%s,%s", oid.name(), packOffset); 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 index 4b70c2cb037..a3cb1151b27 100644 --- 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 @@ -162,7 +162,8 @@ public static MultiPackIndex read(InputStream fd) if (len > Integer.MAX_VALUE - 8) { // http://stackoverflow.com/a/8381338 throw new MultiPackIndexFormatException( - JGitText.get().multiPackIndexFileIsTooLargeForJgit); + MessageFormat.format(JGitText.get().midxChunkTooBig, + chunkId, len)); } byte[] buffer = new byte[(int) len]; 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 index ac6f00c3cc4..cfa5c33be7f 100644 --- 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 @@ -392,6 +392,11 @@ public MutableEntry peek() { public List getPackNames() { return Arrays.asList(midx.getPackNames()); } + + @Override + public void reset() { + position = 0; + } } private static class ReverseIndex { 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 index 4d2e580317a..6b54b5f33be 100644 --- 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 @@ -35,10 +35,10 @@ 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.internal.storage.midx.MultiPackIndex.MutableEntry; import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.util.Base64; import org.eclipse.jgit.util.NB; /** @@ -66,9 +66,11 @@ public class MultiPackIndexWriter { * packs) * @param packNames * packNames + * @param checksum + * checksum of the written midx */ public record Result(long bytesWritten, int objectCount, - List packNames) { + List packNames, String checksum) { } /** @@ -78,17 +80,15 @@ public record Result(long bytesWritten, int objectCount, * 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. + * @param data + * a pack index merger with the data sources (in order) for this + * midx * @return data about the write (e.g. bytes written) * @throws IOException * Error writing to the stream */ public Result write(ProgressMonitor monitor, OutputStream outputStream, - Map inputs) throws IOException { - PackIndexMerger data = new PackIndexMerger(inputs); - + PackIndexMerger data) throws IOException { // List of chunks in the order they need to be written List chunkHeaders = createChunkHeaders(data); long expectedSize = calculateExpectedSize(chunkHeaders); @@ -97,11 +97,14 @@ public Result write(ProgressMonitor monitor, OutputStream outputStream, writeHeader(out, chunkHeaders.size(), data.getPackCount()); writeChunkLookup(out, chunkHeaders); + monitor.beginTask("Writing midx chunks", chunkHeaders.size()); WriteContext ctx = new WriteContext(out, data); for (ChunkHeader chunk : chunkHeaders) { chunk.writerFn.write(ctx); + monitor.update(1); } - writeCheckSum(out); + monitor.endTask(); + byte[] checksum = writeCheckSum(out); if (expectedSize != out.length()) { throw new IllegalStateException(String.format( JGitText.get().multiPackIndexUnexpectedSize, @@ -109,7 +112,7 @@ public Result write(ProgressMonitor monitor, OutputStream outputStream, Long.valueOf(out.length()))); } return new Result(expectedSize, data.getUniqueObjectCount(), - data.getPackNames()); + data.getPackNames(), Base64.encodeBytes(checksum)); } catch (InterruptedIOException e) { throw new IOException(JGitText.get().multiPackIndexWritingCancelled, e); @@ -223,9 +226,9 @@ private void writeChunkLookup(CancellableDigestOutputStream out, private void writeFanoutTable(WriteContext ctx) throws IOException { byte[] tmp = new byte[4]; int[] fanout = new int[256]; - Iterator iterator = ctx.data.bySha1Iterator(); + Iterator iterator = ctx.data.bySha1Iterator(); while (iterator.hasNext()) { - MidxMutableEntry e = iterator.next(); + MutableEntry e = iterator.next(); fanout[e.getObjectId().getFirstByte() & 0xff]++; } for (int i = 1; i < fanout.length; i++) { @@ -250,9 +253,9 @@ private void writeFanoutTable(WriteContext ctx) throws IOException { private void writeOidLookUp(WriteContext ctx) throws IOException { byte[] tmp = new byte[OBJECT_ID_LENGTH]; - Iterator iterator = ctx.data.bySha1Iterator(); + Iterator iterator = ctx.data.bySha1Iterator(); while (iterator.hasNext()) { - MidxMutableEntry e = iterator.next(); + MutableEntry e = iterator.next(); e.getObjectId().copyRawTo(tmp, 0); ctx.out.write(tmp, 0, OBJECT_ID_LENGTH); } @@ -272,9 +275,9 @@ private void writeOidLookUp(WriteContext ctx) throws IOException { */ private void writeObjectOffsets(WriteContext ctx) throws IOException { byte[] entry = new byte[8]; - Iterator iterator = ctx.data.bySha1Iterator(); + Iterator iterator = ctx.data.bySha1Iterator(); while (iterator.hasNext()) { - MidxMutableEntry e = iterator.next(); + MutableEntry e = iterator.next(); NB.encodeInt32(entry, 0, e.getPackId()); if (!ctx.data.needsLargeOffsetsChunk() || fitsIn31bits(e.getOffset())) { @@ -305,10 +308,10 @@ private void writeRidx(WriteContext ctx) throws IOException { // memory. We could also iterate reverse indexes looking up // their position in the midx (and discarding if the pack doesn't // match). - Iterator iterator = ctx.data.bySha1Iterator(); + Iterator iterator = ctx.data.bySha1Iterator(); int midxPosition = 0; while (iterator.hasNext()) { - MidxMutableEntry e = iterator.next(); + MutableEntry e = iterator.next(); OffsetPosition op = new OffsetPosition(e.getOffset(), midxPosition); midxPosition++; packOffsets.computeIfAbsent(e.getPackId(), k -> new ArrayList<>()) @@ -384,13 +387,16 @@ private void writePackfileNames(WriteContext ctx) throws IOException { * * @param out * output stream used to write + * @return the checksum (same value that is written as footer of the file) * @throws IOException * error writing to the output stream */ - private void writeCheckSum(CancellableDigestOutputStream out) + private byte[] writeCheckSum(CancellableDigestOutputStream out) throws IOException { - out.write(out.getDigest()); + byte[] checksum = out.getDigest(); + out.write(checksum); out.flush(); + return checksum; } private record OffsetPosition(long offset, int position) { 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 index 4a296ee6401..9e78930c600 100644 --- 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 @@ -10,14 +10,14 @@ 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 org.eclipse.jgit.internal.storage.file.PackIndex; -import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.MidxIterator; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.MutableEntry; import org.eclipse.jgit.lib.MutableObjectId; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ProgressMonitor; /** * Collect the stats and offers an iterator over the union of n-pack indexes. @@ -32,109 +32,144 @@ * entries. The stats of the combined index are calculated in an iteration at * construction time. */ -class PackIndexMerger { +public class PackIndexMerger { private static final int LIMIT_31_BITS = (1 << 31) - 1; private static final long LIMIT_32_BITS = (1L << 32) - 1; + private final MidxIterator midxIterator; + + private final boolean needsLargeOffsetsChunk; + + private final int offsetsOver31BitsCount; + + private final int uniqueObjectCount; + + private final int[] objectsPerPack; + + private final List packnames; + /** - * Object returned by the iterator. + * Builder collecting the inputs for the merger. *

- * 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. + * Order matters. In case of duplicates, the merger chooses the object in + * the first pack it appears. */ - static class MidxMutableEntry { - // The object id - private final MutableObjectId oid = new MutableObjectId(); + public static class Builder { - // Position of the pack in the ordered list of pack in this merger - private int packId; + private final List packIndexes = new ArrayList<>(); - // Offset in its pack - private long offset; + private ProgressMonitor pm = NullProgressMonitor.INSTANCE; - public AnyObjectId getObjectId() { - return oid; + /** + * Add a regular pack to the midx + * + * @param name + * name of the pack + * @param idx + * primary index of the pack + * @return this builder + */ + public Builder addPack(String name, PackIndex idx) { + packIndexes.add(MidxIterators.fromPackIndexIterator(name, idx)); + return this; } - public int getPackId() { - return packId; + /** + * Add data from this midx iterator to the merge + *

+ * Packs are kept in the order of the iterator. + * + * @param midx + * a midx iterator + * @return this builder + */ + public Builder addMidx(MidxIterator midx) { + packIndexes.add(midx); + return this; } - public long getOffset() { - return offset; + /** + * Add a progress monitor to the build process + *

+ * Give visibility over the first iteration of the packs calculating the + * data needed for midx headers (unique object count, if large offsets + * are needed...) + * + * @param pm + * a progress monitor + * @return this builder + */ + public Builder setProgressMonitor(ProgressMonitor pm) { + this.pm = pm; + return this; } /** - * Copy values from another mutable entry + * Build the merger instance * - * @param packId - * packId - * @param other - * another mutable entry + * @return a merger instance */ - private void fill(int packId, PackIndex.MutableEntry other) { - other.copyOidTo(oid); - this.packId = packId; - this.offset = other.getOffset(); + public PackIndexMerger build() { + return new PackIndexMerger( + MidxIterators.dedup(MidxIterators.join(packIndexes)), pm); } } - private final List packNames; - - private final List indexes; - - private final boolean needsLargeOffsetsChunk; - - private final int offsetsOver31BitsCount; - - private final int uniqueObjectCount; - - private final int[] objectsPerPack; - /** - * Build a common view of these pack indexes - *

- * Order matters: in case of duplicates, the first pack with the object wins + * Create a builder * - * @param packs - * map of pack names to indexes, ordered. + * @return an empty builder */ - PackIndexMerger(Map packs) { - this.packNames = packs.keySet().stream().toList(); - this.indexes = packs.values().stream().toList(); + public static Builder builder() { + return new Builder(); + } - objectsPerPack = new int[packNames.size()]; - // Iterate for duplicates + /** + * A common view of the input pack indexes + * + * @param midxIterator + * MidxIterator built by deduping union of all pack indexes + * @param pm + * a progress monitor + */ + private PackIndexMerger(MidxIterator midxIterator, ProgressMonitor pm) { + this.midxIterator = midxIterator; + this.packnames = midxIterator.getPackNames(); + + objectsPerPack = new int[packnames.size()]; + pm.beginTask("Iterating objects for midx headers", + ProgressMonitor.UNKNOWN); + // Iterate for duplicates and counts that we need to build the chunk + // headers. 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; - } + while (midxIterator.hasNext()) { + MutableEntry entry = midxIterator.next(); // 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) { + if (entry.getOffset() > LIMIT_32_BITS) { hasLargeOffsets = true; } - if (entry.offset > LIMIT_31_BITS) { + if (entry.getOffset() > LIMIT_31_BITS) { over31bits++; } lastSeen.fromObjectId(entry.oid); objectCount++; - objectsPerPack[entry.packId]++; + // TODO(ifrade): we can calculate the fanout table already here. + // It saves an iteration over all objects for only 1Kb of memory + objectsPerPack[entry.getPackId()]++; + pm.update(1); } uniqueObjectCount = objectCount; offsetsOver31BitsCount = over31bits; needsLargeOffsetsChunk = hasLargeOffsets; + pm.endTask(); } /** @@ -142,7 +177,7 @@ private void fill(int packId, PackIndex.MutableEntry other) { * * @return object count of the merged index */ - int getUniqueObjectCount() { + public int getUniqueObjectCount() { return uniqueObjectCount; } @@ -168,7 +203,7 @@ int getOffsetsOver31BitsCount() { } /** - * Number of objects selected for the midx per packid + * Number of objects selected for the midx per pack id * * @return array where position n contains the amount of objects selected * for pack id n @@ -187,7 +222,7 @@ int[] getObjectsPerPack() { * @return List of pack names, in the order used by the merge. */ List getPackNames() { - return packNames; + return packnames; } /** @@ -196,160 +231,22 @@ List getPackNames() { * @return count of packs merged */ int getPackCount() { - return packNames.size(); + return packnames.size(); } /** * Iterator over the merged indexes in sha1 order without duplicates *

+ * This always returns the same iterator resetted. We don't support two + * iterators over this merged data. + *

* 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 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 rawIterator() { - return new MultiIndexIterator(indexes); - } - - /** - * Iterator over n-indexes in ObjectId order. - *

- * 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 { - - private final List indexIterators; - - private final MidxMutableEntry mutableEntry = new MidxMutableEntry(); - - MultiIndexIterator(List 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 { - 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. - *

- * 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. - *

- * 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 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; - } + public MidxIterator bySha1Iterator() { + midxIterator.reset(); + return midxIterator; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityChecker.java new file mode 100644 index 00000000000..cfe6bcf42b0 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityChecker.java @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2026, 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.internal.transport.connectivity; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdSubclassMap; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.ObjectReachabilityChecker; +import org.eclipse.jgit.revwalk.ObjectWalk; +import org.eclipse.jgit.revwalk.ReachabilityChecker; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ConnectivityChecker; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.treewalk.TreeWalk; + +/** + * A connectivity checker that avoids the object allocations that occur when + * doing standard graph coloring via {@code ObjectWalk}. + * + * {@code TreeWalkConnectivityChecker} requires the {@code PackParser} to report + * new objects in the pack, and will fail immediately if that is not configured. + * + * The {@code ObjectWalk}-based algorithm marks objects interesting and + * uninteresting and parses new subtrees and blobs to propagate those states. + * Each propagation of state to a child node requires a Java object allocation. + * This algorithm is closer to the diff algorithm. It parses tree objects at + * common paths and compares hash values in those trees. Objects only need to be + * created for subtrees that differ. + * + * The tree connectivity part of this algorithm always creates O(commits + tree + * objects in the new pack) Java objects, independent of where the parent commit + * is in the graph, and independent of the number of references. (Caveat, it + * does a standard reachability check if a parent commit is not in advertised + * "haves", and a standard object reachability check for any base objects + * referenced in a thin pack.) The {@code ObjectWalk}-based algorithm is + * equivalent to this algorithm when the parents of new commits are all in the + * advertised "haves", creating O(commit + tree objects in the new pack) Java + * objects. It is much less efficient otherwise, creating either O(tree objects + * in checkout) or O(all objects in checkout) Java objects. + * + * This algorithm first validates that the commits in the commands (new branch + * tips) are connected. Starting with those commits, it walks back until a + * commit not in the pack is found, or until a commit with no parents is found. + * If a parent commit id is not in the database, connectivity fails. If the + * parent commit is in the database and was present in the "haves" advertised + * for the client, it moves on to verifying tree connectivity. Otherwise, it + * performs a reachability check to make sure the client has access to the + * unadvertised parent commit, and proceeds to verifying tree connectivity if + * that succeeds. + * + * Tree connectivity is verified for every commit in the receive pack that was + * visited when checking commit connectivity. For each commit, get its root tree + * and the root trees of its parents. For each path segment in the child + * commit's root tree, do the following (includes recursing into differing + * subtrees, where the same actions are applied): + *

    + *
  • if a blob or subtree's id is identical to one of the parent's blob or + * subtree's ids, continue/li> + *
  • if a new blob id is not present in the database, connectivity fails
  • + *
  • if a new subtree id is present in the pack, traverse into the subtree to + * continue the check, performing the same actions in this list
  • + *
  • if the new subtree id is not in the pack but is present in the database, + * continue/li> + *
  • if the new subtree id is not in either the pack or the database, + * connectivity fails
  • + *
+ */ +public class TreeWalkConnectivityChecker implements ConnectivityChecker { + private ObjectIdSubclassMap objectsInPack; + + private Set advertisedHaves; + + @Override + public void checkConnectivity(ConnectivityCheckInfo connectivityCheckInfo, + Set haves, ProgressMonitor pm) throws IOException { + + if (!connectivityCheckInfo.getParser().needNewObjectIds()) { + throw new IllegalStateException( + "PackParser.setNeedNewObjectIds(true) must be set"); //$NON-NLS-1$ + } + + Repository repo = connectivityCheckInfo.getRepository(); + RevWalk rw = connectivityCheckInfo.getWalk(); + this.objectsInPack = connectivityCheckInfo.getParser() + .getNewObjectIds(); + this.advertisedHaves = haves; + + Set nonAdvertisedParentCommitsOutsidePack = new HashSet<>(); + List newCommitsToVerify = extractCommitsToVerify(rw, repo, + connectivityCheckInfo.getCommands(), + nonAdvertisedParentCommitsOutsidePack, pm); + + /* + * This class underreports the full set of objects parsed and does not + * advance the progress monitor in the checkReachability() and + * checkThinPackBases() methods. These methods invoke {@code + * ReachabilityChecker} and @{code ObjectReachabilityChecker}, neither + * of which take a progress monitor. Pushes are generally based on + * commits near branch tips, so the checkers normally do minimal walks. + * Setup for these checkers involves at a minimum marking all "haves" as + * starts, so we capture that in the progress monitor. + */ + if (!nonAdvertisedParentCommitsOutsidePack.isEmpty()) { + pm.update(advertisedHaves.size()); + checkReachability(rw, repo, nonAdvertisedParentCommitsOutsidePack); + } + + checkThinPackBases(rw, connectivityCheckInfo); + + verifyTreeConnectivity(rw, repo, newCommitsToVerify, + connectivityCheckInfo.isCheckObjects(), pm); + } + + /** + * Extracts commits that need to be verified and identifies parent commits + * outside the pack. + * + * @param rw + * the RevWalk to use + * @param repo + * the repository + * @param commands + * the receive commands + * @param nonAdvertisedParentCommitsOutsidePack + * set to populate with parent commits outside the pack and not + * in the advertised set (haves) + * @param pm + * progress monitor + * @return list of new commits in the pack that require verification + * @throws IOException + * if an I/O error occurs + */ + private List extractCommitsToVerify(RevWalk rw, Repository repo, + List commands, + Set nonAdvertisedParentCommitsOutsidePack, + ProgressMonitor pm) throws IOException { + + List newCommitsToVerify = new ArrayList<>(); + + // Gather new commits from the receive commands + for (ReceiveCommand cmd : commands) { + if (cmd.getType() != ReceiveCommand.Type.DELETE + && !advertisedHaves.contains(cmd.getNewId())) { + rw.markStart(rw.parseCommit(cmd.getNewId())); + } + } + + // Walk commits in the receive pack, recording both commits in the pack + // and parent commits outside the pack + RevCommit commit; + while ((commit = rw.next()) != null) { + pm.update(1); + if (objectsInPack.contains(commit)) { + newCommitsToVerify.add(commit); + } else { + // Commit not in pack, check object database + if (!repo.getObjectDatabase().has(commit)) { + throw new MissingObjectException(commit.getId(), + Constants.TYPE_COMMIT); + } + // Advertised parents are reachable, only track non-advertised + if (!advertisedHaves.contains(commit.getId())) { + nonAdvertisedParentCommitsOutsidePack.add(commit); + } + rw.markUninteresting(commit); + } + } + + return newCommitsToVerify; + } + + /** + * Performs reachability checks for parent commits outside the pack. + * + * @param rw + * the RevWalk to use + * @param repo + * the repository + * @param nonAdvertisedParentCommitsOutsidePack + * parent commits to check visibility for + * @throws IOException + * if an I/O error occurs + */ + private void checkReachability(RevWalk rw, Repository repo, + Set nonAdvertisedParentCommitsOutsidePack) + throws IOException { + + try { + // First try with the smaller set of advertised haves + ReachabilityChecker checker = rw.getObjectReader() + .createReachabilityChecker(rw); + Stream starterCommits = advertisedHaves.stream() + .map(id -> parseCommitOrNull(rw, id)).filter(Objects::nonNull); + + Optional unreachable = checker.areAllReachable( + nonAdvertisedParentCommitsOutsidePack, starterCommits); + + if (unreachable.isPresent()) { + // Fallback to check against full ref database + Stream allRefCommits = repo.getRefDatabase() + .getRefs().stream() + .map(ref -> parseCommitOrNull(rw, ref.getObjectId())) + .filter(Objects::nonNull); + unreachable = checker.areAllReachable( + nonAdvertisedParentCommitsOutsidePack, allRefCommits); + if (unreachable.isPresent()) { + throw new MissingObjectException(unreachable.get().getId(), + Constants.TYPE_COMMIT); + } + } + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + /** + * Validates that base objects referenced in a thin pack are reachable. + * + * @param rw + * the RevWalk to use + * @param connectivityCheckInfo + * the connectivity check info + * @throws IOException + * if an I/O error occurs + */ + private void checkThinPackBases(RevWalk rw, + ConnectivityCheckInfo connectivityCheckInfo) throws IOException { + + if (!connectivityCheckInfo.isCheckObjects()) { + return; + } + ObjectIdSubclassMap baseObjectIds = connectivityCheckInfo + .getParser().getBaseObjectIds(); + + try (ObjectWalk ow = new ObjectWalk(rw.getObjectReader())) { + ObjectReachabilityChecker checker = rw.getObjectReader() + .createObjectReachabilityChecker(ow); + + List targetObjs = StreamSupport + .stream(baseObjectIds.spliterator(), false) + .map(id -> parseAnyUnchecked(ow, id)) + .collect(Collectors.toList()); + + // First try with the smaller set of advertised haves + Stream starterObjs = advertisedHaves.stream() + .map(id -> parseAnyUnchecked(ow, id)) + .filter(Objects::nonNull); + + Optional unreachable = checker + .areAllReachable(targetObjs, starterObjs); + if (unreachable.isPresent()) { + // Fallback to check against full ref database + Stream allRefCommits = connectivityCheckInfo + .getRepository().getRefDatabase().getRefs().stream() + .map(ref -> parseAnyUnchecked(ow, ref.getObjectId())) + .filter(Objects::nonNull); + unreachable = checker.areAllReachable(targetObjs, + allRefCommits); + if (unreachable.isPresent()) { + throw new MissingObjectException(unreachable.get().getId(), + Constants.TYPE_COMMIT); + } + } + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + /** + * Verifies tree connectivity for the new commits. + * + * @param rw + * the RevWalk to use + * @param repo + * the repository + * @param newCommitsToVerify + * commits to verify + * @param checkObjects + * whether to check objects + * @param pm + * progress monitor + * @throws IOException + * if an I/O error occurs + */ + private void verifyTreeConnectivity(RevWalk rw, Repository repo, + List newCommitsToVerify, boolean checkObjects, + ProgressMonitor pm) throws IOException { + + for (RevCommit c : newCommitsToVerify) { + verifyTreeConnectivityForCommit(c, rw, repo, checkObjects, pm); + } + } + + /** + * Verifies tree connectivity for a single commit. + * + * @param c + * the commit + * @param rw + * the RevWalk to use + * @param repo + * the repository + * @param checkObjects + * whether to check objects + * @param pm + * progress monitor + * @throws IOException + * if an I/O error occurs + */ + private void verifyTreeConnectivityForCommit(RevCommit c, RevWalk rw, + Repository repo, boolean checkObjects, ProgressMonitor pm) + throws IOException { + try (TreeWalk tw = new TreeWalk(rw.getObjectReader())) { + tw.setRecursive(false); + tw.addTree(c.getTree()); + pm.update(1); + for (RevCommit p : c.getParents()) { + tw.addTree(p.getTree()); + pm.update(1); + } + + while (tw.next()) { + if (tw.getFileMode(0) == FileMode.MISSING) { + continue; // Object deleted or moved + } + + if (tw.getFileMode(0) == FileMode.GITLINK) { + continue; // Skip submodule entries + } + + ObjectId newObjId = tw.getObjectId(0); + if (matchesAnyParent(tw, newObjId)) { + continue; // matched via object ids + } + + if (!tw.isSubtree()) { + /* + * Blob case. objectsInPack are already in the object + * database, but the map lookup is faster than the database + * search, so try the map lookup first. + */ + if (!objectsInPack.contains(newObjId) && (checkObjects + || !repo.getObjectDatabase().has(newObjId))) { + throw new MissingObjectException(newObjId, + tw.getFileMode(0).getObjectType()); + } + } else { + // Subtree case + if (objectsInPack.contains(newObjId)) { + tw.enterSubtree(); + pm.update(1 + c.getParentCount()); + } else if (checkObjects + || !repo.getObjectDatabase().has(newObjId)) { + throw new MissingObjectException(newObjId, + FileMode.TREE.getObjectType()); + } + } // Else object is in the database + } + } + } + + /** + * Parses an object, throwing UncheckedIOException on failure. For use with + * streams. + * + * @param rw + * the RevWalk to use + * @param id + * the object ID + * @return the parsed object + */ + private static RevObject parseAnyUnchecked(RevWalk rw, ObjectId id) { + try { + return rw.parseAny(id); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Parses an object as a commit, peeling tags if necessary. Returns null if + * the object is not a commit or cannot be peeled to a commit. Throws + * UncheckedIOException on other I/O failures. For use with streams. + * + * @param rw + * the RevWalk to use + * @param id + * the object ID + * @return the parsed commit, or null + */ + private static RevCommit parseCommitOrNull(RevWalk rw, ObjectId id) { + try { + return rw.parseCommit(id); + } catch (IncorrectObjectTypeException e) { + return null; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Checks if the new object ID matches any parent tree's object ID at the + * current path. + * + * @param tw + * the TreeWalk + * @param newObjId + * the new object ID + * @return true if matches any parent + */ + private static boolean matchesAnyParent(TreeWalk tw, ObjectId newObjId) { + for (int i = 1; i < tw.getTreeCount(); i++) { + if (tw.getFileMode(i) != FileMode.MISSING + && newObjId.equals(tw.getObjectId(i))) { + return true; + } + } + return false; + } + +} 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 b1ba5dfa280..ae5b2143078 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java @@ -97,11 +97,11 @@ public boolean matchConfigValue(String in) { private final static Charset DEFAULT_COMMIT_MESSAGE_ENCODING = StandardCharsets.UTF_8; - private String i18nCommitEncoding; + private final String i18nCommitEncoding; - private String commitTemplatePath; + private final String commitTemplatePath; - private CleanupMode cleanupMode; + private final CleanupMode cleanupMode; private char commentCharacter = '#'; 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 9de8392690d..5265e76a894 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -839,6 +839,13 @@ public static byte[] encode(String str) { */ public static final int COMMIT_GENERATION_NOT_COMPUTED = 0; + /** + * Name of the .git/objects/packs/multi-pack-index file. + * + * @since 7.7 + */ + public static final String MIDX_FILE = "multi-pack-index"; + private Constants() { // Hide the default constructor } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackedRefsTrait.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackedRefsTrait.java new file mode 100644 index 00000000000..09967189eab --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackedRefsTrait.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2026, Nvidia + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.lib; + +/** + * Headers defined on the packed-refs file. + * + * @since 7.7 + */ +public enum PackedRefsTrait { + /** If in the header, denotes the file has sorted data. */ + SORTED(" sorted"), //$NON-NLS-1$ + /** + * If in the header, denotes the file has peeled data for (refs/tags/...). + */ + PEELED(" peeled"), //$NON-NLS-1$ + /** + * If in the header, denotes the file has peeled data for all the refs which + * are peelable. + */ + FULLY_PEELED(" fully-peeled"); //$NON-NLS-1$ + + private final String value; + + PackedRefsTrait(String value) { + this.value = value; + } + + /** + * Gives the string representation of trait like it appears in packed-refs + * header + * + * @return String representation of the trait. + */ + public String value() { + return value; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackedRefsWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackedRefsWriter.java new file mode 100644 index 00000000000..f198782d203 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PackedRefsWriter.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2008, Charles O'Farrell + * Copyright (C) 2009-2010, Google Inc. + * Copyright (C) 2009, Robin Rosenberg + * Copyright (C) 2008, Shawn O. Pearce and others + * Copyright (C) 2026, Nvidia + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.lib; + +import static org.eclipse.jgit.lib.Constants.R_TAGS; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import org.eclipse.jgit.internal.storage.file.RefDirectory; +import org.eclipse.jgit.util.RefList; + +/** + * Writes out refs to {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file by + * computing and applying all the missing traits for optimized reads. + * + * @since 7.7 + */ +public abstract class PackedRefsWriter { + /** Refs to be written. */ + protected Collection refs; + + /** Traits that are applicable to the refs. */ + protected final EnumSet traits; + + /** + *

+ * Constructor for PackedRefsWriter. + *

+ * + * @param refs + * the complete set of references. This should have been computed + * by applying updates to the advertised refs already discovered. + * @param traits + * traits that are applicable to the refs. If any traits are + * missing, they would be applied before writing, but the + * specified traits are not re-computed/checked. + * @param refDb + * refDb where the packed-refs file should be written. + * + * @throws IOException + * if it is not able to peel any of the tags. + * @since 7.7 + */ + public PackedRefsWriter(Collection refs, + EnumSet traits, RefDatabase refDb) + throws IOException { + this(refs, traits); + applyMissingTraits(refDb); + } + + /** + *

+ * Constructor for PackedRefsWriter. + *

+ * + *

+ * Stores the provided refs and traits without applying any missing traits. + * Intended for use by subclasses that manage trait application themselves. + *

+ * + * @param refs + * the complete set of references. This should have been computed + * by applying updates to the advertised refs already discovered. + * @param traits + * traits that are applicable to the refs. + */ + protected PackedRefsWriter(Collection refs, + EnumSet traits) { + this.refs = refs; + this.traits = traits; + } + + /** + * Rebuild the {@link org.eclipse.jgit.lib.Constants#INFO_REFS}. + *

+ * This method rebuilds the contents of the + * {@link org.eclipse.jgit.lib.Constants#INFO_REFS} file to match the passed + * list of references. + * + * @throws java.io.IOException + * writing is not supported, or attempting to write the file + * failed, possibly due to permissions or remote disk full, etc. + */ + public void writeInfoRefs() throws IOException { + final StringWriter w = new StringWriter(); + final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH]; + for (Ref r : refs) { + if (Constants.HEAD.equals(r.getName())) { + // Historically HEAD has never been published through + // the INFO_REFS file. This is a mistake, but its the + // way things are. + // + continue; + } + + ObjectId objectId = r.getObjectId(); + if (objectId == null) { + // Symrefs to unborn branches aren't advertised in the info/refs + // file. + continue; + } + objectId.copyTo(tmp, w); + w.write('\t'); + w.write(r.getName()); + w.write('\n'); + + ObjectId peeledObjectId = r.getPeeledObjectId(); + if (peeledObjectId != null) { + peeledObjectId.copyTo(tmp, w); + w.write('\t'); + w.write(r.getName()); + w.write("^{}\n"); //$NON-NLS-1$ + } + } + writeFile(Constants.INFO_REFS, Constants.encode(w.toString())); + } + + /** + * Rebuild the {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file. + *

+ * This method rebuilds the contents of the + * {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file to match the + * passed list of references, including only those refs that have a storage + * type of {@link org.eclipse.jgit.lib.Ref.Storage#PACKED}. + * + * @throws java.io.IOException + * writing is not supported, or attempting to write the file + * failed, possibly due to permissions or remote disk full, etc. + */ + public void writePackedRefs() throws IOException { + final StringWriter w = new StringWriter(); + w.write(RefDirectory.PACKED_REFS_HEADER); + for (PackedRefsTrait t : traits) { + w.write(t.value()); + } + w.write('\n'); + + final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH]; + for (Ref r : refs) { + if (r.getStorage() != Ref.Storage.PACKED) + continue; + + ObjectId objectId = r.getObjectId(); + if (objectId == null) { + // A packed ref cannot be a symref, let alone a symref + // to an unborn branch. + throw new NullPointerException(); + } + objectId.copyTo(tmp, w); + w.write(' '); + w.write(r.getName()); + w.write('\n'); + + ObjectId peeledObjectId = r.getPeeledObjectId(); + if (peeledObjectId != null) { + w.write('^'); + peeledObjectId.copyTo(tmp, w); + w.write('\n'); + } + } + writeFile(Constants.PACKED_REFS, Constants.encode(w.toString())); + } + + /** + * Access the new refs after all the necessary traits were applied. + * + * @return refs with all the traits applied + */ + public RefList asRefList() { + RefList.Builder builder = new RefList.Builder<>(this.refs.size()); + for (Ref each : refs) { + builder.add(each); + } + return builder.toRefList(); + } + + /** + * Handles actual writing of ref files to the git repository, which may + * differ slightly depending on the destination and transport. + * + * @param file + * path to ref file. + * @param content + * byte content of file to be written. + * @throws java.io.IOException + * if an IO error occurred + */ + protected abstract void writeFile(String file, byte[] content) + throws IOException; + + private void applyMissingTraits(RefDatabase refDb) throws IOException { + if (!traits.contains(PackedRefsTrait.SORTED)) { + refs = RefComparator.sort(refs); + traits.add(PackedRefsTrait.SORTED); + } + + if (traits.contains(PackedRefsTrait.FULLY_PEELED)) { + // fully-peeled implies peeled. + traits.add(PackedRefsTrait.PEELED); + return; + } + + Collection peeledRefs = new ArrayList<>(); + for (Ref ref : refs) { + if (ref.isPeeled() || (traits.contains(PackedRefsTrait.PEELED) + && ref.getName().startsWith(R_TAGS))) { + // trust refs/tags/... when caller provides peeled trait. + peeledRefs.add(ref); + } else { + peeledRefs.add(refDb.peel(ref)); + } + } + + refs = peeledRefs; + traits.add(PackedRefsTrait.PEELED); + traits.add(PackedRefsTrait.FULLY_PEELED); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java index 58aed82748e..ffa8e09090d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java @@ -13,12 +13,10 @@ package org.eclipse.jgit.lib; -import java.io.IOException; -import java.io.StringWriter; import java.util.Collection; +import java.util.EnumSet; import java.util.Map; -import org.eclipse.jgit.internal.storage.file.RefDirectory; import org.eclipse.jgit.util.RefList; import org.eclipse.jgit.util.RefMap; @@ -28,158 +26,75 @@ * * This class is abstract as the writing of the files must be handled by the * caller. This is because it is used by transport classes as well. + * + * @deprecated since 7.7 + * + * Contains a bug in trait handling; retained for backward compatibility + * and will be removed in the next version. Use {@link PackedRefsWriter} + * instead. */ -public abstract class RefWriter { - - private final Collection refs; +@Deprecated(since = "7.7") +public abstract class RefWriter extends PackedRefsWriter { /** - *

Constructor for RefWriter.

+ *

+ * Constructor for RefWriter. + *

* * @param refs * the complete set of references. This should have been computed * by applying updates to the advertised refs already discovered. */ + @Deprecated(since = "7.7") public RefWriter(Collection refs) { - this.refs = RefComparator.sort(refs); + super(RefComparator.sort(refs), EnumSet.of(PackedRefsTrait.SORTED)); + if (containsAnyPeeledRef(this.refs)) { + this.traits.add(PackedRefsTrait.PEELED); + } } /** - *

Constructor for RefWriter.

+ *

+ * Constructor for RefWriter. + *

* * @param refs * the complete set of references. This should have been computed * by applying updates to the advertised refs already discovered. */ + @Deprecated(since = "7.7") public RefWriter(Map refs) { - if (refs instanceof RefMap) - this.refs = refs.values(); - else - this.refs = RefComparator.sort(refs.values()); + super(refs instanceof RefMap ? refs.values() + : RefComparator.sort(refs.values()), + EnumSet.of(PackedRefsTrait.SORTED)); + if (containsAnyPeeledRef(this.refs)) { + this.traits.add(PackedRefsTrait.PEELED); + } } /** - *

Constructor for RefWriter.

+ *

+ * Constructor for RefWriter. + *

* * @param refs * the complete set of references. This should have been computed * by applying updates to the advertised refs already discovered. */ + @Deprecated(since = "7.7") public RefWriter(RefList refs) { - this.refs = refs.asList(); - } - - /** - * Rebuild the {@link org.eclipse.jgit.lib.Constants#INFO_REFS}. - *

- * This method rebuilds the contents of the - * {@link org.eclipse.jgit.lib.Constants#INFO_REFS} file to match the passed - * list of references. - * - * @throws java.io.IOException - * writing is not supported, or attempting to write the file - * failed, possibly due to permissions or remote disk full, etc. - */ - public void writeInfoRefs() throws IOException { - final StringWriter w = new StringWriter(); - final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH]; - for (Ref r : refs) { - if (Constants.HEAD.equals(r.getName())) { - // Historically HEAD has never been published through - // the INFO_REFS file. This is a mistake, but its the - // way things are. - // - continue; - } - - ObjectId objectId = r.getObjectId(); - if (objectId == null) { - // Symrefs to unborn branches aren't advertised in the info/refs - // file. - continue; - } - objectId.copyTo(tmp, w); - w.write('\t'); - w.write(r.getName()); - w.write('\n'); - - ObjectId peeledObjectId = r.getPeeledObjectId(); - if (peeledObjectId != null) { - peeledObjectId.copyTo(tmp, w); - w.write('\t'); - w.write(r.getName()); - w.write("^{}\n"); //$NON-NLS-1$ - } + super(refs.asList(), EnumSet.of(PackedRefsTrait.SORTED)); + if (containsAnyPeeledRef(this.refs)) { + this.traits.add(PackedRefsTrait.PEELED); } - writeFile(Constants.INFO_REFS, Constants.encode(w.toString())); } - /** - * Rebuild the {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file. - *

- * This method rebuilds the contents of the - * {@link org.eclipse.jgit.lib.Constants#PACKED_REFS} file to match the - * passed list of references, including only those refs that have a storage - * type of {@link org.eclipse.jgit.lib.Ref.Storage#PACKED}. - * - * @throws java.io.IOException - * writing is not supported, or attempting to write the file - * failed, possibly due to permissions or remote disk full, etc. - */ - public void writePackedRefs() throws IOException { - boolean peeled = false; + private boolean containsAnyPeeledRef(Collection refs) { for (Ref r : refs) { if (r.getStorage().isPacked() && r.isPeeled()) { - peeled = true; - break; - } - } - - final StringWriter w = new StringWriter(); - if (peeled) { - w.write(RefDirectory.PACKED_REFS_HEADER); - w.write(RefDirectory.PACKED_REFS_PEELED); - w.write(RefDirectory.PACKED_REFS_SORTED); - w.write('\n'); - } - - final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH]; - for (Ref r : refs) { - if (r.getStorage() != Ref.Storage.PACKED) - continue; - - ObjectId objectId = r.getObjectId(); - if (objectId == null) { - // A packed ref cannot be a symref, let alone a symref - // to an unborn branch. - throw new NullPointerException(); - } - objectId.copyTo(tmp, w); - w.write(' '); - w.write(r.getName()); - w.write('\n'); - - ObjectId peeledObjectId = r.getPeeledObjectId(); - if (peeledObjectId != null) { - w.write('^'); - peeledObjectId.copyTo(tmp, w); - w.write('\n'); + return true; } } - writeFile(Constants.PACKED_REFS, Constants.encode(w.toString())); + return false; } - - /** - * Handles actual writing of ref files to the git repository, which may - * differ slightly depending on the destination and transport. - * - * @param file - * path to ref file. - * @param content - * byte content of file to be written. - * @throws java.io.IOException - * if an IO error occurred - */ - protected abstract void writeFile(String file, byte[] content) - throws IOException; } 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 c9dc6da4ba5..01a43611cf9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -1375,6 +1375,8 @@ public RepositoryState getRepositoryState() { * * For portability reasons '\' is excluded * + * @see git-check-ref-format(1) manual page * @param refName a {@link java.lang.String} object. * @return true if refName is a valid ref name */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAttributes.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAttributes.java new file mode 100644 index 00000000000..3d0c0a5d4b2 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAttributes.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2026 Vector Informatik GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.merge; + +import org.eclipse.jgit.attributes.Attributes; +import org.eclipse.jgit.attributes.AttributesNodeProvider; +import org.eclipse.jgit.treewalk.TreeWalk; + +/** + * Provides {@link Attributes} for the trees during content-merge of a three way + * merge + * + * @since 7.8 + */ +public interface MergeAttributes { + + /** + * Attributes used when the {@link TreeWalk} has no + * {@link AttributesNodeProvider} + */ + static MergeAttributes NO_ATTRIBUTES = new MergeAttributes() { + + private static final Attributes EMPTY_ATTRIBUTES = new Attributes(); + + @Override + public Attributes base() { + return EMPTY_ATTRIBUTES; + } + + @Override + public Attributes ours() { + return EMPTY_ATTRIBUTES; + } + + @Override + public Attributes theirs() { + return EMPTY_ATTRIBUTES; + } + }; + + /** + * Retrieve the {@link Attributes} for the common base between ours and + * theirs + * + * @return {@link Attributes} for the common base between ours and theirs + */ + Attributes base(); + + /** + * Retrieve the {@link Attributes} for the 'ours' side of the merge + * + * @return {@link Attributes} for the 'ours' side of the merge + */ + Attributes ours(); + + /** + * Retrieve the {@link Attributes} for the 'theirs' side of the merge + * + * @return {@link Attributes} for the 'theirs' side of the merge + */ + Attributes theirs(); + +} \ No newline at end of file diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java index 54b7aa4346b..680e3e4b816 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java @@ -9,8 +9,13 @@ *******************************************************************************/ package org.eclipse.jgit.merge; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; + import java.io.IOException; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config.SectionParser; @@ -60,6 +65,8 @@ public static final SectionParser getParser( private final FastForwardMode fastForwardMode; + private final ConflictStyle conflictStyle; + private final boolean squash; private final boolean commit; @@ -67,12 +74,14 @@ public static final SectionParser getParser( private MergeConfig(String branch, Config config) { String[] mergeOptions = getMergeOptions(branch, config); fastForwardMode = getFastForwardMode(config, mergeOptions); + conflictStyle = getConflictStyle(config); squash = isMergeConfigOptionSet("--squash", mergeOptions); //$NON-NLS-1$ commit = !isMergeConfigOptionSet("--no-commit", mergeOptions); //$NON-NLS-1$ } private MergeConfig() { fastForwardMode = FastForwardMode.FF; + conflictStyle = ConflictStyle.MERGE; squash = false; commit = true; } @@ -86,6 +95,16 @@ public FastForwardMode getFastForwardMode() { return fastForwardMode; } + /** + * Get the configured conflict style + * + * @return the configured conflict style + * @since 7.6 + */ + public ConflictStyle getConflictStyle() { + return conflictStyle; + } + /** * Whether merges into this branch are configured to be squash merges, false * otherwise @@ -120,6 +139,11 @@ private static FastForwardMode getFastForwardMode(Config config, return ffmode; } + private ConflictStyle getConflictStyle(Config config) { + return config.getEnum(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + private static boolean isMergeConfigOptionSet(String optionToLookFor, String[] mergeOptions) { for (String option : mergeOptions) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index dc96f65b878..8aeb7bfb724 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -16,9 +16,12 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.time.Instant.EPOCH; +import static org.eclipse.jgit.api.MergeCommand.ConflictStyle.MERGE; import static org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm.HISTOGRAM; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONFLICTSTYLE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import java.io.Closeable; @@ -39,6 +42,7 @@ import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.api.MergeCommand.ConflictStyle; import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.attributes.Attributes; import org.eclipse.jgit.attributes.AttributesNodeProvider; @@ -831,6 +835,8 @@ public enum MergeFailureReason { */ protected MergeAlgorithm mergeAlgorithm; + private ConflictStyle conflictStyle; + /** * The {@link ContentMergeStrategy} to use for "resolve" and "recursive" * merges. @@ -856,8 +862,6 @@ private static String[] defaultCommitNames() { return new String[]{"BASE", "OURS", "THEIRS"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } - private static final Attributes NO_ATTRIBUTES = new Attributes(); - /** * Constructor for ResolveMerger. * @@ -870,6 +874,7 @@ protected ResolveMerger(Repository local, boolean inCore) { super(local); Config config = local.getConfig(); mergeAlgorithm = getMergeAlgorithm(config); + conflictStyle = getConflictStyle(config); commitNames = defaultCommitNames(); this.inCore = inCore; } @@ -896,6 +901,7 @@ protected ResolveMerger(Repository local) { protected ResolveMerger(ObjectInserter inserter, Config config) { super(inserter); mergeAlgorithm = getMergeAlgorithm(config); + conflictStyle = getConflictStyle(config); commitNames = defaultCommitNames(); inCore = true; } @@ -923,6 +929,23 @@ public void setContentMergeStrategy(ContentMergeStrategy strategy) { : strategy; } + /** + * Sets the conflict style to be used when formatting merge conflicts. + * + * @param conflictStyle + * a {@link org.eclipse.jgit.api.MergeCommand.ConflictStyle} + * @since 7.6 + */ + public void setConflictStyle(ConflictStyle conflictStyle) { + this.conflictStyle = conflictStyle; + } + + private ConflictStyle getConflictStyle(Config config) { + return config.getEnum(CONFIG_MERGE_SECTION, + null, + CONFIG_KEY_CONFLICTSTYLE, MERGE); + } + @Override protected boolean mergeImpl() throws IOException { return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1], @@ -996,20 +1019,23 @@ private DirCacheEntry keep(DirCacheEntry e) { * @param entry * to add * @param attributes - * the {@link Attributes} of the trees + * the {@link Attributes} of the trees. Must not be retained + * outside of the scope of the method invocation * @throws IOException * if the {@link CheckoutMetadata} cannot be determined - * @since 6.1 + * @since 7.8 */ protected void addToCheckout(String path, DirCacheEntry entry, - Attributes[] attributes) - throws IOException { - EolStreamType cleanupStreamType = workTreeUpdater.detectCheckoutStreamType(attributes[T_OURS]); - String cleanupSmudgeCommand = tw.getSmudgeCommand(attributes[T_OURS]); - EolStreamType checkoutStreamType = workTreeUpdater.detectCheckoutStreamType(attributes[T_THEIRS]); - String checkoutSmudgeCommand = tw.getSmudgeCommand(attributes[T_THEIRS]); - workTreeUpdater.addToCheckout(path, entry, cleanupStreamType, cleanupSmudgeCommand, - checkoutStreamType, checkoutSmudgeCommand); + MergeAttributes attributes) throws IOException { + EolStreamType cleanupStreamType = workTreeUpdater + .detectCheckoutStreamType(attributes.ours()); + String cleanupSmudgeCommand = tw.getSmudgeCommand(attributes.ours()); + EolStreamType checkoutStreamType = workTreeUpdater + .detectCheckoutStreamType(attributes.theirs()); + String checkoutSmudgeCommand = tw.getSmudgeCommand(attributes.theirs()); + workTreeUpdater.addToCheckout(path, entry, cleanupStreamType, + cleanupSmudgeCommand, checkoutStreamType, + checkoutSmudgeCommand); } /** @@ -1074,18 +1100,19 @@ protected void addDeletion(String path, boolean isFile, * see * {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)} * @param attributes - * the {@link Attributes} for the three trees + * the {@link Attributes} for the three trees. Must not be + * retained outside of the scope of the method invocation * @return false if the merge will fail because the index entry * didn't match ours or the working-dir file was dirty and a * conflict occurred * @throws java.io.IOException * if an IO error occurred - * @since 6.1 + * @since 7.8 */ protected boolean processEntry(CanonicalTreeParser base, CanonicalTreeParser ours, CanonicalTreeParser theirs, DirCacheBuildIterator index, WorkingTreeIterator work, - boolean ignoreConflicts, Attributes[] attributes) + boolean ignoreConflicts, MergeAttributes attributes) throws IOException { enterSubtree = true; final int modeO = tw.getRawMode(T_OURS); @@ -1203,7 +1230,7 @@ protected boolean processEntry(CanonicalTreeParser base, // Base, ours, and theirs all contain a folder: don't delete return true; } - addDeletion(tw.getPathString(), nonTree(modeO), attributes[T_OURS]); + addDeletion(tw.getPathString(), nonTree(modeO), attributes.ours()); return true; } @@ -1250,7 +1277,7 @@ protected boolean processEntry(CanonicalTreeParser base, if (nonTree(modeO) && nonTree(modeT)) { // Check worktree before modifying files boolean worktreeDirty = isWorktreeDirty(work, ourDce); - if (!attributes[T_OURS].canBeContentMerged() && worktreeDirty) { + if (!attributes.ours().canBeContentMerged() && worktreeDirty) { return false; } @@ -1267,7 +1294,7 @@ protected boolean processEntry(CanonicalTreeParser base, mergeResults.put(tw.getPathString(), result); unmergedPaths.add(tw.getPathString()); return true; - } else if (!attributes[T_OURS].canBeContentMerged()) { + } else if (!attributes.ours().canBeContentMerged()) { // File marked as binary switch (getContentMergeStrategy()) { case OURS: @@ -1321,7 +1348,7 @@ protected boolean processEntry(CanonicalTreeParser base, } else if (ignoreConflicts) { result.setContainsConflicts(false); } - updateIndex(base, ours, theirs, result, attributes[T_OURS]); + updateIndex(base, ours, theirs, result, attributes.ours()); workTreeUpdater.markAsModified(currentPath); // Entry is null - only add the metadata addToCheckout(currentPath, null, attributes); @@ -1436,7 +1463,7 @@ protected boolean processEntry(CanonicalTreeParser base, // conflict markers). But also stage 0 of the index // is filled with that content. updateIndex(base, ours, theirs, result, - attributes[T_OURS]); + attributes.ours()); } } else { DirCacheEntry e = addConflict(base, ours, theirs); @@ -1488,7 +1515,8 @@ private static MergeResult createGitLinksMergeResult( * @param theirs * used to parse theirs tree * @param attributes - * attributes for the different stages + * attributes for the different stages. Must not be retained + * outside of the scope of the method invocation * @param strategy * merge strategy * @@ -1500,19 +1528,18 @@ private static MergeResult createGitLinksMergeResult( */ private MergeResult contentMerge(CanonicalTreeParser base, CanonicalTreeParser ours, CanonicalTreeParser theirs, - Attributes[] attributes, ContentMergeStrategy strategy) + MergeAttributes attributes, ContentMergeStrategy strategy) throws BinaryBlobException, IOException { // TW: The attributes here are used to determine the LFS smudge filter. // Is doing a content merge on LFS items really a good idea?? RawText baseText = base == null ? RawText.EMPTY_TEXT - : getRawText(base.getEntryObjectId(), attributes[T_BASE]); + : getRawText(base.getEntryObjectId(), attributes.base()); RawText ourText = ours == null ? RawText.EMPTY_TEXT - : getRawText(ours.getEntryObjectId(), attributes[T_OURS]); + : getRawText(ours.getEntryObjectId(), attributes.ours()); RawText theirsText = theirs == null ? RawText.EMPTY_TEXT - : getRawText(theirs.getEntryObjectId(), attributes[T_THEIRS]); + : getRawText(theirs.getEntryObjectId(), attributes.theirs()); mergeAlgorithm.setContentMergeStrategy( - getAttributesContentMergeStrategy(attributes[T_OURS], - strategy)); + getAttributesContentMergeStrategy(attributes.ours(), strategy)); return mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText, ourText, theirsText); } @@ -1668,8 +1695,16 @@ private TemporaryBuffer doMerge(MergeResult result) db != null ? nonNullRepo().getDirectory() : null, workTreeUpdater.getInCoreFileSizeLimit()); boolean success = false; try { - new MergeFormatter().formatMerge(buf, result, - Arrays.asList(commitNames), UTF_8); + switch (conflictStyle) { + case MERGE: + new MergeFormatter().formatMerge(buf, result, + Arrays.asList(commitNames), UTF_8); + break; + case DIFF3: + new MergeFormatter().formatMergeDiff3(buf, result, + Arrays.asList(commitNames), UTF_8); + break; + } buf.close(); success = true; } finally { @@ -1975,14 +2010,11 @@ protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts) boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE; boolean hasAttributeNodeProvider = treeWalk .getAttributesNodeProvider() != null; + MergeAttributes attributes = hasAttributeNodeProvider + ? new CurrentTreeWalkEntryMergeAttributes(treeWalk) + : MergeAttributes.NO_ATTRIBUTES; + while (treeWalk.next()) { - Attributes[] attributes = {NO_ATTRIBUTES, NO_ATTRIBUTES, - NO_ATTRIBUTES}; - if (hasAttributeNodeProvider) { - attributes[T_BASE] = treeWalk.getAttributes(T_BASE); - attributes[T_OURS] = treeWalk.getAttributes(T_OURS); - attributes[T_THEIRS] = treeWalk.getAttributes(T_THEIRS); - } if (!processEntry( treeWalk.getTree(T_BASE, CanonicalTreeParser.class), treeWalk.getTree(T_OURS, CanonicalTreeParser.class), @@ -2000,4 +2032,33 @@ protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts) } return true; } + + // Uses the caching mechanism in TreeWalk.getAttributes() to retrieve the + // Attributes of the current path only when requested. When the TreeWalk + // advances to the next entry, the mapping of tree index -> cached + // attributes is also cleared + private static final class CurrentTreeWalkEntryMergeAttributes implements MergeAttributes { + + private final TreeWalk walk; + + public CurrentTreeWalkEntryMergeAttributes(TreeWalk treeWalk) { + walk = treeWalk; + } + + @Override + public Attributes base() { + return walk.getAttributes(T_BASE); + } + + @Override + public Attributes ours() { + return walk.getAttributes(T_OURS); + } + + @Override + public Attributes theirs() { + return walk.getAttributes(T_THEIRS); + } + + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java index fa109e82086..d301b47376a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java @@ -47,7 +47,20 @@ public class PlotCommit extends RevCommit { * the identity of this commit. */ protected PlotCommit(AnyObjectId id) { - super(id); + this(id, -1); + } + + /** + * Create a new commit. + * + * @param id + * the identity of this commit. + * @param graphPosition + * the position of this commit in the commit graph + * @since 7.8 + */ + protected PlotCommit(AnyObjectId id, int graphPosition) { + super(id, graphPosition); forkingOffLanes = NO_LANES; passingLanes = NO_LANES; mergingLanes = NO_LANES; 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 c8c454a228e..88c2d23e731 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java @@ -105,8 +105,8 @@ public void sort(RevSort s, boolean use) { } @Override - protected RevCommit createCommit(AnyObjectId id) { - return new PlotCommit(id); + protected RevCommit createCommit(AnyObjectId id, int graphPos) { + return new PlotCommit(id, graphPos); } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractCommitRewriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractCommitRewriter.java new file mode 100644 index 00000000000..b33c846a27e --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractCommitRewriter.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2008, Shawn O. Pearce 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.revwalk; + +import java.io.IOException; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; + +abstract class AbstractCommitRewriter { + + /** For {@link #cleanup(RevCommit[])} to remove duplicate parents. */ + private static final int DUPLICATE = RevWalk.TEMP_MARK; + + private final boolean firstParent; + + AbstractCommitRewriter(boolean firstParent) { + this.firstParent = firstParent; + } + + /** + * Makes sure that the {@link TreeRevFilter} has been applied to all parents + * of this commit + * + * @param c + * given commit + * @throws MissingObjectException + * if an object is missing + * @throws IncorrectObjectTypeException + * if an object has an unexpected type + * @throws IOException + * if an IO error occurred + */ + abstract void applyFilterToParents(RevCommit c) + throws MissingObjectException, IncorrectObjectTypeException, + IOException; + + final RevCommit rewriteParents(RevCommit c) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + applyFilterToParents(c); + + boolean rewrote = false; + RevCommit[] pList = c.getParents(); + int nParents = pList.length; + for (int i = 0; i < nParents; i++) { + RevCommit oldp = pList[i]; + RevCommit newp = rewrite(oldp); + if (firstParent) { + if (newp == null) { + c.parents = RevCommit.NO_PARENTS; + } else { + c.parents = new RevCommit[] { newp }; + } + return c; + } + if (oldp != newp) { + pList[i] = newp; + rewrote = true; + } + } + if (rewrote) { + c.parents = cleanup(pList); + } + return c; + } + + private RevCommit rewrite(RevCommit p) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + while (true) { + + if (p.getParentCount() > 1) { + // This parent is a merge, so keep it. + // + return p; + } + + if ((p.flags & RevWalk.UNINTERESTING) != 0) { + // Retain uninteresting parents. They show where the + // DAG was cut off because it wasn't interesting. + // + return p; + } + + if ((p.flags & RevWalk.REWRITE) == 0) { + // This parent was not eligible for rewriting. We + // need to keep it in the DAG. + // + return p; + } + + if (p.getParentCount() == 0) { + // We can't go back any further, other than to + // just delete the parent entirely. + // + return null; + } + + applyFilterToParents(p.getParent(0)); + p = p.getParent(0); + + } + } + + private RevCommit[] cleanup(RevCommit[] oldList) { + // Remove any duplicate parents caused due to rewrites (e.g. a merge + // with two sides that both simplified back into the merge base). + // We also may have deleted a parent by marking it null. + // + int newCnt = 0; + for (int o = 0; o < oldList.length; o++) { + RevCommit p = oldList[o]; + if (p == null) { + continue; + } + if ((p.flags & DUPLICATE) != 0) { + oldList[o] = null; + continue; + } + p.flags |= DUPLICATE; + newCnt++; + } + + if (newCnt == oldList.length) { + for (RevCommit p : oldList) { + p.flags &= ~DUPLICATE; + } + return oldList; + } + + RevCommit[] newList = new RevCommit[newCnt]; + newCnt = 0; + for (RevCommit p : oldList) { + if (p != null) { + newList[newCnt++] = p; + p.flags &= ~DUPLICATE; + } + } + + return newList; + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java index 7795ce2d3bd..cd0bd234944 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java @@ -125,9 +125,23 @@ public boolean isBoundary() { * object name for the commit. */ protected Commit(AnyObjectId id) { - super(id); + this(id, -1); + } + + /** + * Initialize a new commit. + * + * @param id + * object name for the commit. + * @param graphPosition + * the position of this commit in the commit graph + * @since 7.8 + */ + protected Commit(AnyObjectId id, int graphPosition) { + super(id, graphPosition); depth = -1; } + } /** Subclass of RevWalk that performs depth filtering. */ @@ -196,8 +210,8 @@ public void markRoot(RevCommit c) throws MissingObjectException, } @Override - protected RevCommit createCommit(AnyObjectId id) { - return new Commit(id); + protected RevCommit createCommit(AnyObjectId id, int graphPos) { + return new Commit(id, graphPos); } @Override @@ -367,8 +381,8 @@ public void markUnshallow(RevObject c) throws MissingObjectException, } @Override - protected RevCommit createCommit(AnyObjectId id) { - return new Commit(id); + protected RevCommit createCommit(AnyObjectId id, int graphPos) { + return new Commit(id, graphPos); } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java index 926e45d9313..add181d3cc6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java @@ -72,16 +72,16 @@ class PendingGenerator extends Generator { */ private int overScan = OVER_SCAN; - boolean canDispose; + private final boolean canDispose; - PendingGenerator(final RevWalk w, final DateRevQueue p, - final RevFilter f, final int out) { + PendingGenerator(RevWalk w, DateRevQueue p, RevFilter f, int out, + boolean canDispose) { super(w.isFirstParent()); - walker = w; - pending = p; - filter = f; - output = out; - canDispose = true; + this.walker = w; + this.pending = p; + this.filter = f; + this.output = out; + this.canDispose = canDispose; } @Override 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 871545fca2b..17896543d7a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java @@ -23,9 +23,11 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.storage.commitgraph.ChangedPathFilter; +import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.MutableObjectId; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.PersonIdent; @@ -133,6 +135,10 @@ public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException { */ protected byte[] buffer; + private final int graphPosition; + + private int generation = Constants.COMMIT_GENERATION_UNKNOWN; + /** * Create a new commit reference. * @@ -140,17 +146,31 @@ public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException { * object name for the commit. */ protected RevCommit(AnyObjectId id) { + this(id, -1); + } + + /** + * Create a new commit reference. + * + * @param id + * object name for the commit. + * @param graphPosition + * the position of this commit in the commit graph + * @since 7.8 + */ + protected RevCommit(AnyObjectId id, int graphPosition) { super(id); + this.graphPosition = graphPosition; } @Override - void parseHeaders(RevWalk walk) throws MissingObjectException, + final void parseHeaders(RevWalk walk) throws MissingObjectException, IncorrectObjectTypeException, IOException { parseCanonical(walk, walk.getCachedBytes(this)); } @Override - void parseBody(RevWalk walk) throws MissingObjectException, + final void parseBody(RevWalk walk) throws MissingObjectException, IncorrectObjectTypeException, IOException { if (buffer == null) { buffer = walk.getCachedBytes(this); @@ -159,11 +179,25 @@ void parseBody(RevWalk walk) throws MissingObjectException, } } - void parseCanonical(RevWalk walk, byte[] raw) throws IOException { + final void parseCanonical(RevWalk walk, byte[] raw) throws IOException { if (!walk.shallowCommitsInitialized) { walk.initializeShallowCommits(this); } + if (graphPosition >= 0) { + if (walk.isRetainBody()) { + buffer = raw; + } + + parseInGraph(walk); + } else { + parseFromObject(walk, raw); + } + + flags |= PARSED; + } + + final void parseFromObject(RevWalk walk, byte[] raw) { final MutableObjectId idBuffer = walk.idBuffer; idBuffer.fromString(raw, 5); tree = walk.lookupTree(idBuffer); @@ -217,7 +251,36 @@ void parseCanonical(RevWalk walk, byte[] raw) throws IOException { if (walk.isRetainBody()) { buffer = raw; } - flags |= PARSED; + } + + final void parseInGraph(RevWalk walk) { + CommitGraph graph = walk.commitGraph(); + CommitGraph.CommitData data = graph.getCommitData(graphPosition); + if (data == null) { + // parseInGraph was called because we know this commit's + // position in the commit graph. If now the commit-graph doesn't + // know about it, something went wrong. + throw new IllegalStateException(); + } + + this.tree = walk.lookupTree(data.getTree()); + this.commitTime = (int) data.getCommitTime(); + this.generation = data.getGeneration(); + + if (getParents() == null) { + int[] pGraphList = data.getParents(); + if (pGraphList.length == 0) { + this.parents = RevCommit.NO_PARENTS; + } else { + RevCommit[] pList = new RevCommit[pGraphList.length]; + for (int i = 0; i < pList.length; i++) { + int graphPos = pGraphList[i]; + ObjectId objId = graph.getObjectId(graphPos); + pList[i] = walk.lookupCommit(objId, graphPos); + } + this.parents = pList; + } + } } @Override @@ -655,8 +718,31 @@ public final List getFooterLines(FooterKey key) { * @return the generation number * @since 6.5 */ - int getGeneration() { - return Constants.COMMIT_GENERATION_UNKNOWN; + final int getGeneration() { + return generation; + } + + /** + * Get the distance of the commit from the root, as defined in + * {@link CommitGraph} + *

+ * This method differs from {@link #getGeneration()} in that it will never + * return {@link Constants#COMMIT_GENERATION_NOT_COMPUTED}. If the + * Generation number was not calculated for this commit, then + * {@link Constants#COMMIT_GENERATION_UNKNOWN} will be returned instead. + * + * @return the generation number, never + * {@link Constants#COMMIT_GENERATION_NOT_COMPUTED} + * @since 7.8 + */ + final int getEffectiveGeneration() { + int gen = getGeneration(); + + if (gen == Constants.COMMIT_GENERATION_NOT_COMPUTED) { + return Constants.COMMIT_GENERATION_UNKNOWN; + } + + return gen; } /** @@ -666,11 +752,16 @@ int getGeneration() { * commit graph file, or the commit graph file was generated without changed * path filters. * - * @param rw A revwalk to load the commit graph (if available) + * @param rw + * A revwalk to load the commit graph (if available) * @return the changed path filter * @since 6.7 */ public ChangedPathFilter getChangedPathFilter(RevWalk rw) { + if (graphPosition >= 0) { + return rw.commitGraph().getChangedPathFilter(graphPosition); + } + return null; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitCG.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitCG.java deleted file mode 100644 index c7a03992b76..00000000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommitCG.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2023, Tencent. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -package org.eclipse.jgit.revwalk; - -import java.io.IOException; - -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.internal.storage.commitgraph.ChangedPathFilter; -import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; -import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.ObjectId; - -/** - * RevCommit parsed from - * {@link org.eclipse.jgit.internal.storage.commitgraph.CommitGraph}. - * - * @since 6.5 - */ -class RevCommitCG extends RevCommit { - - private final int graphPosition; - - private int generation = Constants.COMMIT_GENERATION_UNKNOWN; - - /** - * Create a new commit reference. - * - * @param id - * object name for the commit. - * @param graphPosition - * the position in the commit-graph of the object. - */ - protected RevCommitCG(AnyObjectId id, int graphPosition) { - super(id); - this.graphPosition = graphPosition; - } - - @Override - void parseCanonical(RevWalk walk, byte[] raw) throws IOException { - if (walk.isRetainBody()) { - buffer = raw; - } - parseInGraph(walk); - } - - @Override - void parseHeaders(RevWalk walk) throws MissingObjectException, - IncorrectObjectTypeException, IOException { - if (walk.isRetainBody()) { - super.parseBody(walk); // This parses header and body - return; - } - parseInGraph(walk); - } - - private void parseInGraph(RevWalk walk) throws IOException { - CommitGraph graph = walk.commitGraph(); - CommitGraph.CommitData data = graph.getCommitData(graphPosition); - if (data == null) { - // RevCommitCG was created because we got its graphPosition from - // commit-graph. If now the commit-graph doesn't know about it, - // something went wrong. - throw new IllegalStateException(); - } - if (!walk.shallowCommitsInitialized) { - walk.initializeShallowCommits(this); - } - - this.tree = walk.lookupTree(data.getTree()); - this.commitTime = (int) data.getCommitTime(); - this.generation = data.getGeneration(); - - if (getParents() == null) { - int[] pGraphList = data.getParents(); - if (pGraphList.length == 0) { - this.parents = RevCommit.NO_PARENTS; - } else { - RevCommit[] pList = new RevCommit[pGraphList.length]; - for (int i = 0; i < pList.length; i++) { - int graphPos = pGraphList[i]; - ObjectId objId = graph.getObjectId(graphPos); - pList[i] = walk.lookupCommit(objId, graphPos); - } - this.parents = pList; - } - } - flags |= PARSED; - } - - @Override - int getGeneration() { - return generation; - } - - /** {@inheritDoc} */ - @Override - public ChangedPathFilter getChangedPathFilter(RevWalk rw) { - return rw.commitGraph().getChangedPathFilter(graphPosition); - } -} 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 8e604baa638..448e6e02366 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java @@ -179,7 +179,7 @@ public class RevWalk implements Iterable, AutoCloseable { */ static final int RESERVED_FLAGS = 9; - private static final int APP_FLAGS = -1 & ~((1 << RESERVED_FLAGS) - 1); + static final int APP_FLAGS = -1 & ~((1 << RESERVED_FLAGS) - 1); final ObjectReader reader; @@ -971,10 +971,10 @@ public RevCommit lookupCommit(AnyObjectId id) { } /** - * This method is intended to be invoked only by {@link RevCommitCG}, in - * order to give commit the correct graphPosition before accessing the - * commit-graph. In this way, the headers of the commit can be obtained in - * constant time. + * This method is intended to be invoked only by + * {@link RevCommit#parseInGraph(RevWalk)}, in order to give commit the + * correct graphPosition before accessing the commit-graph. In this way, the + * headers of the commit can be obtained in constant time. * * @param id * name of the commit object. @@ -1526,6 +1526,32 @@ void freeFlag(int mask) { } } + /** + * Arrange for flags to be recycled at the next {@code reset}. + *

+ * Unlike {@link #freeFlag(int)}, this always defers: the flags + * join the {@link #delayFreeFlags} set and are only returned to the + * {@link #freeFlags} by an invocation of a {@code reset} method. If the + * flags were marked {@code retainOnReset}, that request is cleared. + *

+ * Only call this while a {@link Generator} is under + * construction - i.e. from within the call chain of + * {@link StartGenerator#next()}. At that point {@link #pending} is still + * the {@link StartGenerator}, so {@link #isNotStarted()} reports + * {@code true} and {@link #freeFlag(int)} would return the flags to + * {@link #freeFlags} immediately. The next {@link #newFlag(String)} would + * then hand the same bits to an unrelated caller, silently corrupting both + * walks. Calling this from anywhere else is almost certainly a mistake; use + * {@link #disposeFlag(RevFlag)} instead. + * + * @param mask + * the flag bits to recycle at the next {@code reset}. + */ + final void freeFlagOnReset(int mask) { + retainOnReset &= ~mask; + delayFreeFlags |= mask; + } + private void finishDelayedFreeFlags() { if (delayFreeFlags != 0) { freeFlags |= delayFreeFlags; @@ -1764,16 +1790,28 @@ public ObjectWalk toObjectWalkWithSameObjects() { * @param id * the object this walker requires a commit reference for. * @return a new unparsed reference for the object. + * + * @nooverride Since 7.8 This method is not intended to be re-implemented or + * extended by clients. Override + * {@link #createCommit(AnyObjectId, int)} instead. */ protected RevCommit createCommit(AnyObjectId id) { return createCommit(id, commitGraph().findGraphPosition(id)); } - private RevCommit createCommit(AnyObjectId id, int graphPos) { - if (graphPos >= 0) { - return new RevCommitCG(id, graphPos); - } - return new RevCommit(id); + /** + * Construct a new unparsed commit for the given object. + * + * @param id + * the object this walker requires a commit reference for. + * @param graphPos + * the position of the commit in the commit graph or {@code -1} + * if the commit is not present in the commit graph + * @return a new unparsed reference for the object. + * @since 7.8 + */ + protected RevCommit createCommit(AnyObjectId id, int graphPos) { + return new RevCommit(id, graphPos); } void carryFlagsImpl(RevCommit c) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java index 4bfe2fda021..2da163b719b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java @@ -195,4 +195,27 @@ public static List findBranchesReachableFrom(RevCommit commit, return result; } + /** + * If not already parsed, parses the headers of the given commit using the + * given Rev Walker + * + * @param commit + * The commit to parse + * @param walker + * The RevWalk to be used + * @throws MissingObjectException + * if the object is missing + * @throws IncorrectObjectTypeException + * if the object has an unexpected type + * @throws IOException + * if an IO error occurred + */ + static void ensureHeadersParsed(RevCommit commit, RevWalk walker) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { + if ((commit.flags & RevWalk.PARSED) == 0) { + commit.parseHeaders(walker); + } + } + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java index 4a93f4d745c..0e18f942ec6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java @@ -29,19 +29,18 @@ * @see TreeRevFilter */ class RewriteGenerator extends Generator { - private static final int REWRITE = RevWalk.REWRITE; - - /** For {@link #cleanup(RevCommit[])} to remove duplicate parents. */ - private static final int DUPLICATE = RevWalk.TEMP_MARK; private final Generator source; private final FIFORevQueue pending; + private final AbstractCommitRewriter rewriter; + RewriteGenerator(Generator s) { super(s.firstParent); source = s; pending = new FIFORevQueue(s.firstParent); + rewriter = new PendingRewriter(); } @Override @@ -54,7 +53,6 @@ int outputType() { return source.outputType() & ~NEEDS_REWRITE; } - @SuppressWarnings("ReferenceEquality") @Override RevCommit next() throws MissingObjectException, IncorrectObjectTypeException, IOException { @@ -69,137 +67,46 @@ RevCommit next() throws MissingObjectException, } } - applyFilterToParents(c); - - boolean rewrote = false; - final RevCommit[] pList = c.getParents(); - final int nParents = pList.length; - for (int i = 0; i < nParents; i++) { - final RevCommit oldp = pList[i]; - final RevCommit newp = rewrite(oldp); - if (firstParent) { - if (newp == null) { - c.parents = RevCommit.NO_PARENTS; - } else { - c.parents = new RevCommit[] { newp }; - } - return c; - } - if (oldp != newp) { - pList[i] = newp; - rewrote = true; - } - } - if (rewrote) { - c.parents = cleanup(pList); - } - return c; - } - - /** - * Makes sure that the {@link TreeRevFilter} has been applied to all parents - * of this commit by the previous {@link PendingGenerator}. - * - * @param c - * given commit - * @throws MissingObjectException - * if an object is missing - * @throws IncorrectObjectTypeException - * if an object has an unexpected type - * @throws IOException - * if an IO error occurred - */ - private void applyFilterToParents(RevCommit c) - throws MissingObjectException, IncorrectObjectTypeException, - IOException { - for (RevCommit parent : c.getParents()) { - while ((parent.flags & RevWalk.TREE_REV_FILTER_APPLIED) == 0) { - - RevCommit n = source.next(); - - if (n != null) { - pending.add(n); - } else { - // Source generator is exhausted; filter has been applied to - // all commits - return; - } - - } - - } + return rewriter.rewriteParents(c); } - private RevCommit rewrite(RevCommit p) throws MissingObjectException, - IncorrectObjectTypeException, IOException { - for (;;) { - - if (p.getParentCount() > 1) { - // This parent is a merge, so keep it. - // - return p; - } - - if ((p.flags & RevWalk.UNINTERESTING) != 0) { - // Retain uninteresting parents. They show where the - // DAG was cut off because it wasn't interesting. - // - return p; - } - - if ((p.flags & REWRITE) == 0) { - // This parent was not eligible for rewriting. We - // need to keep it in the DAG. - // - return p; - } - - if (p.getParentCount() == 0) { - // We can't go back any further, other than to - // just delete the parent entirely. - // - return null; - } - - applyFilterToParents(p.getParent(0)); - p = p.getParent(0); - + class PendingRewriter extends AbstractCommitRewriter { + PendingRewriter() { + super(firstParent); } - } - private RevCommit[] cleanup(RevCommit[] oldList) { - // Remove any duplicate parents caused due to rewrites (e.g. a merge - // with two sides that both simplified back into the merge base). - // We also may have deleted a parent by marking it null. - // - int newCnt = 0; - for (int o = 0; o < oldList.length; o++) { - final RevCommit p = oldList[o]; - if (p == null) - continue; - if ((p.flags & DUPLICATE) != 0) { - oldList[o] = null; - continue; - } - p.flags |= DUPLICATE; - newCnt++; - } + /** + * Makes sure that the {@link TreeRevFilter} has been applied to all + * parents of this commit by the previous {@link PendingGenerator}. + * + * @param c + * given commit + * @throws MissingObjectException + * if an object is missing + * @throws IncorrectObjectTypeException + * if an object has an unexpected type + * @throws IOException + * if an IO error occurred + */ + @Override + void applyFilterToParents(RevCommit c) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + for (RevCommit parent : c.getParents()) { + while ((parent.flags & RevWalk.TREE_REV_FILTER_APPLIED) == 0) { + + RevCommit n = source.next(); + + if (n != null) { + pending.add(n); + } else { + // Source generator is exhausted; filter has been + // applied to all commits + return; + } - if (newCnt == oldList.length) { - for (RevCommit p : oldList) - p.flags &= ~DUPLICATE; - return oldList; - } + } - final RevCommit[] newList = new RevCommit[newCnt]; - newCnt = 0; - for (RevCommit p : oldList) { - if (p != null) { - newList[newCnt++] = p; - p.flags &= ~DUPLICATE; } } - - return newList; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java index 6854b6083df..2d4cc09837f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java @@ -110,18 +110,33 @@ RevCommit next() throws MissingObjectException, walker.queue = q; + if (walker.hasRevSort(RevSort.TOPO) + && walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER)) { + throw new IllegalStateException(JGitText + .get().cannotCombineTopoSortWithTopoKeepBranchTogetherSort); + } + if (walker instanceof DepthWalk) { DepthWalk dw = (DepthWalk) walker; g = new DepthGenerator(dw, pending); + + if (walker.hasRevSort(RevSort.TOPO)) { + g = new TopoSortGenerator(g); + } } else { - g = new PendingGenerator(w, pending, rf, pendingOutputType); - - if (walker.hasRevSort(RevSort.BOUNDARY)) { - // Because the boundary generator may produce uninteresting - // commits we cannot allow the pending generator to dispose - // of them early. - // - ((PendingGenerator) g).canDispose = false; + // Because the boundary generator may produce uninteresting + // commits we cannot allow the pending generator to dispose + // of them early. + // + boolean canDispose = !walker.hasRevSort(RevSort.BOUNDARY); + + if (walker.hasRevSort(RevSort.TOPO)) { + // Doesn't need rewrite + g = new TopoSortPendingGenerator(w, pending, rf, + pendingOutputType, canDispose); + } else { + g = new PendingGenerator(w, pending, rf, pendingOutputType, + canDispose); } } @@ -129,16 +144,7 @@ RevCommit next() throws MissingObjectException, g = new RewriteGenerator(g); } - if (walker.hasRevSort(RevSort.TOPO) - && walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER)) { - throw new IllegalStateException(JGitText - .get().cannotCombineTopoSortWithTopoKeepBranchTogetherSort); - } - - if (walker.hasRevSort(RevSort.TOPO) - && (g.outputType() & SORT_TOPO) == 0) { - g = new TopoSortGenerator(g); - } else if (walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER) + if (walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER) && (g.outputType() & SORT_TOPO) == 0) { g = new TopoNonIntermixSortGenerator(g); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoExplorePhase.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoExplorePhase.java new file mode 100644 index 00000000000..ca810731eef --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoExplorePhase.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2026 Vector Informatik GmbH + * + * 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.revwalk; + +import java.io.IOException; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.revwalk.filter.RevFilter; + +final class TopoExplorePhase extends TopoPhase { + + private final RevFlag topoPassedFilterFlag; + + private final RevFilter filter; + + private final boolean canDispose; + + TopoExplorePhase(RevWalk walker, RevFilter filter, + boolean canDispose) { + super(walker, "EXPLORE"); //$NON-NLS-1$ + this.topoPassedFilterFlag = walker.newFlag("TOPO_PASSED_FILTER"); //$NON-NLS-1$ + this.filter = filter; + this.canDispose = canDispose; + } + + void explore(int minGeneration) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + RevCommit c; + while ((c = tryRemove(minGeneration)) != null) { + if (!propagateUninteresting(c) && passThroughFilter(c)) { + c.add(topoPassedFilterFlag); + } + + for (RevCommit p : c.getParents()) { + enqueue(p); + } + } + } + + @Override + int getAllocatedFlags() { + return super.getAllocatedFlags() | topoPassedFilterFlag.mask; + } + + boolean hasPassedFilter(RevCommit c) { + return c.has(topoPassedFilterFlag); + } + + private boolean propagateUninteresting(RevCommit c) { + walker.carryFlagsImpl(c); + return c.has(RevFlag.UNINTERESTING); + } + + private boolean passThroughFilter(RevCommit c) + throws MissingObjectException, + IncorrectObjectTypeException, IOException { + boolean hadBody = c.getRawBuffer() != null; + + if (filter.requiresCommitBody() && !hadBody) { + c.parseBody(walker); + } + + boolean passesFilter = filter.include(walker, c); + + if (!hadBody && canDispose) { + c.disposeBody(); + } + + return passesFilter; + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoInDegreePhase.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoInDegreePhase.java new file mode 100644 index 00000000000..0efcc359bac --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoInDegreePhase.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2026 Vector Informatik GmbH + * + * 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.revwalk; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.lib.Constants; + +final class TopoInDegreePhase extends TopoPhase { + + private final TopoExplorePhase explorePhase; + + private final AbstractCommitRewriter rewriter; + + private final RevFlag topoSeen; + + private final AbstractRevQueue ready; + + private int minGeneration = Constants.COMMIT_GENERATION_UNKNOWN; + + TopoInDegreePhase(RevWalk walker, TopoExplorePhase explorePhase, + boolean needsRewrite) { + super(walker, "INDEGREE"); //$NON-NLS-1$ + + this.explorePhase = explorePhase; + this.rewriter = needsRewrite ? new TopoRewriter() : null; + this.topoSeen = walker.newFlag("TOPO_SEEN"); //$NON-NLS-1$ + this.ready = RevWalk.newDateRevQueue(walker.isFirstParent()); + } + + void initialize(AbstractRevQueue p) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + List roots = new ArrayList<>(); + + for (RevCommit root = p.next(); root != null; root = p.next()) { + roots.add(root); + checkUpdateMinGeneration(root); + + explorePhase.enqueue(root); + enqueue(root); + } + + calculateInDegrees(minGeneration); + + for (RevCommit root : roots) { + checkAddReady(root); + } + } + + void calculateInDegrees(int cutoff) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + RevCommit c; + + while ((c = tryRemove(cutoff)) != null) { + // Only perform inDegree calculation on commits, whose history has + // been rewritten + c = rewriteIfNeeded(c); + + visitChild(c); + } + } + + private RevCommit rewriteIfNeeded(RevCommit c) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { + explorePhase.explore(c.getEffectiveGeneration()); + + if (rewriter != null) { + return rewriter.rewriteParents(c); + } + + return c; + } + + private void visitChild(RevCommit c) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + for (RevCommit p : c.getParents()) { + if (p.has(RevFlag.UNINTERESTING) || p.has(RevFlag.UNSHALLOW)) { + continue; + } + + p.inDegree++; + enqueue(p); + + if (walker.isFirstParent()) { + break; + } + } + } + + RevCommit nextReady() throws MissingObjectException, + IncorrectObjectTypeException, IOException { + RevCommit c = ready.next(); + + if (c == null) { + return null; + } + + expand(c); + return c; + } + + @Override + int getAllocatedFlags() { + return super.getAllocatedFlags() | topoSeen.mask; + } + + private void expand(RevCommit c) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + for (RevCommit p : c.getParents()) { + if (p.has(RevFlag.UNINTERESTING)) { + continue; + } + + if (checkUpdateMinGeneration(p)) { + calculateInDegrees(minGeneration); + } + + p.inDegree--; + checkAddReady(p); + + if (walker.isFirstParent()) { + return; + } + } + } + + private void checkAddReady(RevCommit p) { + if (p.inDegree == 0 && !p.has(topoSeen)) { + p.add(topoSeen); + ready.add(p); + } + } + + private boolean checkUpdateMinGeneration(RevCommit c) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { + RevWalkUtils.ensureHeadersParsed(c, walker); + int generation = c.getEffectiveGeneration(); + + if (generation < minGeneration) { + minGeneration = generation; + return true; + } + + return false; + } + + private class TopoRewriter extends AbstractCommitRewriter { + + TopoRewriter() { + super(walker.isFirstParent()); + } + + @Override + void applyFilterToParents(RevCommit c) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + for (RevCommit p : c.getParents()) { + if ((p.flags & RevWalk.TREE_REV_FILTER_APPLIED) == 0) { + RevWalkUtils.ensureHeadersParsed(p, walker); + explorePhase.explore(p.getEffectiveGeneration()); + } + } + + } + + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoPhase.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoPhase.java new file mode 100644 index 00000000000..ea1a3ab5bdd --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoPhase.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2026 Vector Informatik GmbH + * + * 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.revwalk; + +import java.io.IOException; +import java.util.PriorityQueue; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; + +class TopoPhase { + + private final RevFlag testFlag; + + private final PriorityQueue queue; + + protected final RevWalk walker; + + TopoPhase(RevWalk walker, String name) { + this.walker = walker; + this.testFlag = walker.newFlag(name + "_SEEN"); //$NON-NLS-1$ + this.queue = new PriorityQueue<>(TopoPhase::compareGenThenDate); + } + + private static int compareGenThenDate(RevCommit a, RevCommit b) { + int genCompare = Integer.compare(b.getEffectiveGeneration(), + a.getEffectiveGeneration()); + + if (genCompare != 0) { + return genCompare; + } + + return Integer.compare(b.commitTime, a.commitTime); + } + + final void enqueue(RevCommit c) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + if (!c.has(testFlag)) { + RevWalkUtils.ensureHeadersParsed(c, walker); + c.add(testFlag); + queue.offer(c); + } + } + + /** + * If the queue is not empty and the head of the queue has an effective + * generation equal to or higher than {@code minGeneration}, it is removed + * from the queue and returned. + *

+ * Otherwise, {@code null} is returned + * + * @param minGeneration + * The minimum desired generation number + * @return The head of the queue or {@code null} + */ + final RevCommit tryRemove(int minGeneration) { + RevCommit candidate = queue.peek(); + + if (candidate == null) { + return null; + } + + // No need to parse the commit before querying generation, since only + // parsed commits can be added to the queue + if (candidate.getEffectiveGeneration() >= minGeneration) { + queue.remove(); + return candidate; + } + + return null; + } + + int getAllocatedFlags() { + return testFlag.mask; + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortPendingGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortPendingGenerator.java new file mode 100644 index 00000000000..80b0de81813 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortPendingGenerator.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026 Vector Informatik GmbH + * + * 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.revwalk; + +import java.io.IOException; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.revwalk.filter.RevFilter; + +class TopoSortPendingGenerator extends Generator { + + private final int output; + + private final TopoExplorePhase explorePhase; + + private final TopoInDegreePhase inDegreePhase; + + protected TopoSortPendingGenerator(RevWalk walker, AbstractRevQueue pending, + RevFilter filter, int output, boolean canDispose) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { + super(walker.isFirstParent()); + + this.output = (output | SORT_COMMIT_TIME_DESC | SORT_TOPO) + & ~NEEDS_REWRITE; + this.explorePhase = new TopoExplorePhase(walker, filter, canDispose); + this.inDegreePhase = new TopoInDegreePhase(walker, explorePhase, + (output & NEEDS_REWRITE) != 0); + + inDegreePhase.initialize(pending); + + int allocatedFlags = explorePhase.getAllocatedFlags(); + allocatedFlags |= inDegreePhase.getAllocatedFlags(); + walker.freeFlagOnReset(allocatedFlags); + } + + @Override + int outputType() { + return output; + } + + @Override + RevCommit next() throws MissingObjectException, + IncorrectObjectTypeException, IOException { + while (true) { + RevCommit c = inDegreePhase.nextReady(); + + if (c == null) { + return null; + } + + c.add(RevFlag.SEEN); + + if (explorePhase.hasPassedFilter(c)) { + return c; + } + } + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java index 64a1eb2e1a1..bc68daf9a84 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java @@ -690,7 +690,8 @@ public long getOffloadedPackfilesSize() { * @return total time spent processing this pack. */ public long getTimeTotal() { - return statistics.timeCounting + statistics.timeSearchingForReuse + return statistics.timeNegotiating + statistics.timeCounting + + statistics.timeSearchingForReuse + statistics.timeSearchingForSizes + statistics.timeCompressing + statistics.timeWriting; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java index 9a96fdcf37d..415c1ce9e08 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java @@ -14,7 +14,6 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import java.util.Collection; @@ -173,9 +172,11 @@ protected TransportException noRepository(Throwable cause) { * if any exception occurs. * @since 3.0 */ + @SuppressWarnings("Finally") protected void doPush(final ProgressMonitor monitor, final Map refUpdates, OutputStream outputStream) throws TransportException { + Throwable suppressedThrowable = null; try { writeCommands(refUpdates.values(), monitor, outputStream); @@ -183,28 +184,45 @@ protected void doPush(final ProgressMonitor monitor, transmitOptions(); if (writePack) writePack(refUpdates, monitor); - if (sentCommand) { - if (capableReport) - readStatusReport(refUpdates); - if (capableSideBand) { - // Ensure the data channel is at EOF, so we know we have - // read all side-band data from all channels and have a - // complete copy of the messages (if any) buffered from - // the other data channels. - // - int b = in.read(); - if (0 <= b) { - throw new TransportException(uri, MessageFormat.format( - JGitText.get().expectedEOFReceived, - Character.valueOf((char) b))); - } - } - } } catch (TransportException e) { + suppressedThrowable = e; throw e; } catch (Exception e) { - throw new TransportException(uri, e.getMessage(), e); + TransportException transportException = new TransportException(uri, e.getMessage(), e); + suppressedThrowable = transportException; + throw transportException; } finally { + try { + if (sentCommand) { + if (capableReport) { + readStatusReport(refUpdates); + } + if (capableSideBand) { + // Ensure the data channel is at EOF, so we know we have + // read all side-band data from all channels and have a + // complete copy of the messages (if any) buffered from + // the other data channels. + // + int b = in.read(); + if (0 <= b) { + throw new TransportException(uri, MessageFormat.format( + JGitText.get().expectedEOFReceived, + Character.valueOf((char) b))); + } + } + } + } catch (TransportException e) { + if (suppressedThrowable != null) { + e.addSuppressed(suppressedThrowable); + } + throw e; + } catch (Exception e) { + TransportException transportException = new TransportException(uri, e.getMessage(), e); + if (suppressedThrowable != null) { + transportException.addSuppressed(suppressedThrowable); + } + throw transportException; + } if (in instanceof SideBandInputStream) { ((SideBandInputStream) in).drainMessages(); } @@ -324,12 +342,7 @@ private void writePack(final Map refUpdates, writer.setReuseValidatingObjects(false); writer.setDeltaBaseAsOffset(capableOfsDelta); writer.preparePack(monitor, newObjects, remoteObjects); - - OutputStream packOut = out; - if (capableSideBand) { - packOut = new CheckingSideBandOutputStream(in, out); - } - writer.writePack(monitor, monitor, packOut); + writer.writePack(monitor, monitor, out); packTransferTime = writer.getStatistics().getTimeWriting(); } @@ -429,48 +442,4 @@ public List getPushOptions() { public boolean isUseBitmaps() { return useBitmaps; } - - private static class CheckingSideBandOutputStream extends OutputStream { - private final InputStream in; - private final OutputStream out; - - CheckingSideBandOutputStream(InputStream in, OutputStream out) { - this.in = in; - this.out = out; - } - - @Override - public void write(int b) throws IOException { - write(new byte[] { (byte) b }); - } - - @Override - public void write(byte[] buf, int ptr, int cnt) throws IOException { - try { - out.write(buf, ptr, cnt); - } catch (IOException e) { - throw checkError(e); - } - } - - @Override - public void flush() throws IOException { - try { - out.flush(); - } catch (IOException e) { - throw checkError(e); - } - } - - private IOException checkError(IOException e1) { - try { - in.read(); - } catch (TransportException e2) { - return e2; - } catch (IOException e2) { - return e1; - } - return e1; - } - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java index c510194ee6a..e4304426f03 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java @@ -139,6 +139,18 @@ private void executeImp(final ProgressMonitor monitor, final TagOpt tagopt = transport.getTagOpt(); String getTags = (tagopt == TagOpt.NO_TAGS) ? null : Constants.R_TAGS; String getHead = null; + // Snapshot local refs before opening the fetch connection when the + // fetch has positive refspecs or may run AUTO_FOLLOW. Those are the + // paths that can later create TrackingRefUpdates from this fetch and + // need a stable expected-old-id baseline to turn concurrent local ref + // changes into LOCK_FAILURE. + // + // Skip the snapshot for the remaining cases to avoid an unnecessary + // local ref scan when this fetch cannot reach those update paths. + if (!toFetch.isEmpty() || tagopt == TagOpt.AUTO_FOLLOW) { + localRefs(); + } + try { // If we don't have a HEAD yet, we're cloning and need to get the // upstream HEAD, too. @@ -235,10 +247,23 @@ else if (tagopt == TagOpt.FETCH_TAGS) addUpdateBatchCommands(result, batch); for (ReceiveCommand cmd : batch.getCommands()) { cmd.updateType(walk); - if (cmd.getType() == UPDATE_NONFASTFORWARD - && cmd instanceof TrackingRefUpdate.Command - && !((TrackingRefUpdate.Command) cmd).canForceUpdate()) + if (!(cmd instanceof TrackingRefUpdate.Command) + || ((TrackingRefUpdate.Command) cmd).canForceUpdate()) { + continue; + } + + ObjectId currentId = currentObjectId(cmd.getRefName()); + // The initial type check used the ref value snapshotted when + // the fetch started. If the local ref moved since then, + // re-check the non-fast-forward against the current ref before + // executing the batch so non-forced rejects remain REJECTED + // instead of surfacing as LOCK_FAILURE. + ReceiveCommand refreshedCmd = new ReceiveCommand(currentId, + cmd.getNewId(), cmd.getRefName()); + refreshedCmd.updateType(walk); + if (refreshedCmd.getType() == UPDATE_NONFASTFORWARD) { cmd.setResult(REJECTED_NONFASTFORWARD); + } } if (transport.isDryRun()) { for (ReceiveCommand cmd : batch.getCommands()) { @@ -574,6 +599,14 @@ private Map localRefs() throws TransportException { return localRefs; } + private ObjectId currentObjectId(String refName) throws IOException { + Ref current = transport.local.exactRef(refName); + if (current == null) { + return ObjectId.zeroId(); + } + return current.getObjectId(); + } + private void deleteStaleTrackingRefs(FetchResult result, BatchRefUpdate batch) throws IOException { Set processed = new HashSet<>(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java index c55fb21d949..49cf5502583 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchResult.java @@ -63,4 +63,26 @@ public void addSubmodule(String path, FetchResult result) { public Map submoduleResults() { return Collections.unmodifiableMap(submodules); } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder sb = new StringBuilder("FetchResult["); + sb.append("ref updates: "); + sb.append(forMerge.size()); + if (!submodules.isEmpty()) { + sb.append(","); + sb.append("submodules: "); + sb.append(submodules.size()); + } + String messages = getMessages(); + if (!messages.isEmpty()) { + sb.append(","); + sb.append("messages: "); + sb.append(messages.substring(0, + Math.min(100, messages.length()) - 1)); + } + sb.append("]"); + return sb.toString(); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java index e1f2b19ce5d..e842f47f66d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java @@ -254,7 +254,13 @@ public void setNeedNewObjectIds(boolean b) { newObjectIds = null; } - private boolean needNewObjectIds() { + /** + * Whether the parser is configured to keep track of new objects. + * + * @return {@code true} if new objects are tracked, {@code false} otherwise. + * @since 7.7 + */ + public boolean needNewObjectIds() { return newObjectIds != null; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index 3d9c81c90ed..c0ff5bf33f6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java @@ -34,6 +34,8 @@ import java.io.OutputStream; import java.io.UncheckedIOException; import java.text.MessageFormat; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -220,6 +222,8 @@ public class ReceivePack { private boolean checkReferencedAreReachable; + private boolean retainParsedObjectIDs; + /** Git object size limit */ private long maxObjectSizeLimit; @@ -236,6 +240,8 @@ public class ReceivePack { private PushCertificate pushCert; private ReceivedPackStatistics stats; + private long timeReceiving; + private long timeCheckingConnectivity; /** * Connectivity checker to use. @@ -496,6 +502,27 @@ public void setCheckReferencedObjectsAreReachable(boolean b) { this.checkReferencedAreReachable = b; } + /** + * Whether the {@code PackParser} should retain object IDs. + * + * @return {@code true} if the parsed object IDs should be retained. + * @since 7.7 + */ + public boolean isRetainParsedObjectIDs() { + return retainParsedObjectIDs; + } + + /** + * Set whether the {@code PackParser} should retain object IDs. + * + * @param retain + * {@code true} to retain the parsed object IDs. + * @since 7.7 + */ + public void setRetainParsedObjectIDs(boolean retain) { + this.retainParsedObjectIDs = retain; + } + /** * Whether this class expects a bi-directional pipe opened between the * client and itself. @@ -1103,8 +1130,9 @@ public long getPackSize() { * @return if the client is a shallow repository, the list of edge commits * that define the client's shallow boundary. Empty set if the * client is earlier than Git 1.9, or is a full clone. + * @since 7.7 */ - private Set getClientShallowCommits() { + protected Set getClientShallowCommits() { return clientShallowCommits; } @@ -1202,11 +1230,16 @@ private Map getAdvertisedOrDefaultRefs() throws IOException { */ protected void receivePackAndCheckConnectivity() throws IOException, LargeObjectException, SubmoduleValidationException { + Instant start = Instant.now(); receivePack(); + timeReceiving = Duration.between(start, Instant.now()).toMillis(); + if (needCheckConnectivity()) { checkSubmodules(); checkConnectivity(); } + timeCheckingConnectivity = Duration.between(start, Instant.now()) + .toMillis() - timeReceiving; parser = null; } @@ -1537,7 +1570,7 @@ private void receivePack() throws IOException { parser = ins.newPackParser(packInputStream()); parser.setAllowThin(true); - parser.setNeedNewObjectIds(checkReferencedAreReachable); + parser.setNeedNewObjectIds(checkReferencedAreReachable || retainParsedObjectIDs); parser.setNeedBaseObjectIds(checkReferencedAreReachable); parser.setCheckEofAfterPackFooter(!biDirectionalPipe && !isExpectDataAfterPackFooter()); @@ -1648,6 +1681,18 @@ private void validateCommands() { continue; } + if (cmd.getRefName().startsWith(Constants.R_REFS) + && !Repository.isValidRefName( + cmd.getRefName().substring(Constants.R_REFS.length()) + ) + ) { + // Reject the creation of one level references such as + // refs/master to match cgit implementation. + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().funnyRefname); + continue; + } + if (ref != null) { // A well behaved client shouldn't have sent us a // create command for a ref we advertised to it. @@ -1743,8 +1788,18 @@ private void validateCommands() { } } - if (!cmd.getRefName().startsWith(Constants.R_REFS) - || !Repository.isValidRefName(cmd.getRefName())) { + if (!cmd.getRefName().startsWith(Constants.R_REFS)) { + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().funnyRefname); + } + + if (!Repository.isValidRefName(cmd.getRefName()) + // But accept deletion of one level refs (refs/main) + && !( + cmd.getType() == ReceiveCommand.Type.DELETE + && Repository.isValidRefName(cmd.getRefName().substring(Constants.R_REFS.length())) + ) + ) { cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().funnyRefname); } @@ -2226,6 +2281,7 @@ public void receiveWithExceptionPropagation(InputStream input, } private void service() throws IOException { + Instant startNegotiating = Instant.now(); if (isBiDirectionalPipe()) { sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); pckOut.flush(); @@ -2235,6 +2291,8 @@ private void service() throws IOException { return; recvCommands(); + long timeNegotiating = Duration.between(startNegotiating, Instant.now()) + .toMillis(); if (hasCommands()) { try (PostReceiveExecutor e = new PostReceiveExecutor()) { @@ -2249,6 +2307,8 @@ private void service() throws IOException { } } + Instant startProcessing = Instant.now(); + long timePreReceiveHooks = 0; try { setAtomic(isCapabilityEnabled(CAPABILITY_ATOMIC)); @@ -2257,8 +2317,10 @@ private void service() throws IOException { failPendingCommands(); } + Instant startPreReceive = Instant.now(); preReceive.onPreReceive( this, filterCommands(Result.NOT_ATTEMPTED)); + timePreReceiveHooks = Duration.between(startPreReceive, Instant.now()).toMillis(); if (atomic && anyRejects()) { failPendingCommands(); } @@ -2266,6 +2328,18 @@ private void service() throws IOException { } finally { unlockPack(); } + long timeProcessingCommands = Duration + .between(startProcessing, Instant.now()).toMillis() - timePreReceiveHooks; + + ReceivedPackStatistics.Builder statsBuilder = stats != null + ? ReceivedPackStatistics.Builder.toBuilder(stats) + : new ReceivedPackStatistics.Builder(); + stats = statsBuilder.setTimeNegotiating(timeNegotiating) + .setTimeReceiving(timeReceiving) + .setTimeCheckingConnectivity(timeCheckingConnectivity) + .setTimePreReceiveHooks(timePreReceiveHooks) + .setTimeProcessingCommands(timeProcessingCommands) + .build(); sendStatusReport(null); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java index 8887e263eab..39fadd69e41 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java @@ -34,6 +34,12 @@ public class ReceivedPackStatistics { private long numDeltaBlob; private long numDeltaTag; + private long timeNegotiating; + private long timeReceiving; + private long timeCheckingConnectivity; + private long timePreReceiveHooks; + private long timeProcessingCommands; + /** * Get number of bytes read from the input stream * @@ -155,6 +161,59 @@ public long getNumDeltaTag() { return numDeltaTag; } + /** + * Get time in milliseconds spent in the negotiation phase + * + * @return time in milliseconds spent in the negotiation phase + * @since 7.7 + */ + public long getTimeNegotiating() { + return timeNegotiating; + } + + /** + * Get time in milliseconds spent receiving the pack + * + * @return time in milliseconds spent receiving the pack + * @since 7.7 + */ + public long getTimeReceiving() { + return timeReceiving; + } + + /** + * Get time in milliseconds spent checking the connectivity of the received + * pack + * + * @return time in milliseconds spent checking the connectivity of the + * received pack + * @since 7.7 + */ + public long getTimeCheckingConnectivity() { + return timeCheckingConnectivity; + } + + /** + * Get time in milliseconds spent in pre-receive hooks + * + * @return time in milliseconds spent in pre-receive hooks + * @since 7.7 + */ + public long getTimePreReceiveHooks() { + return timePreReceiveHooks; + } + + /** + * Get time in milliseconds spent processing commands (validation + * and ref updates) + * + * @return time in milliseconds spent processing commands + * @since 7.7 + */ + public long getTimeProcessingCommands() { + return timeProcessingCommands; + } + /** A builder for {@link ReceivedPackStatistics}. */ public static class Builder { private long numBytesRead; @@ -173,6 +232,41 @@ public static class Builder { private long numDeltaBlob; private long numDeltaTag; + private long timeNegotiating; + private long timeReceiving; + private long timeCheckingConnectivity; + private long timePreReceiveHooks; + private long timeProcessingCommands; + + /** + * Initialize from an existing ReceivedPackStatistics. + * + * @param s + * existing ReceivedPackStatistics object + * @return new Builder instance + * @since 7.7 + */ + public static Builder toBuilder(ReceivedPackStatistics s) { + Builder b = new Builder(); + b.numBytesRead = s.getNumBytesRead(); + b.numWholeCommit = s.getNumWholeCommit(); + b.numWholeTree = s.getNumWholeTree(); + b.numWholeBlob = s.getNumWholeBlob(); + b.numWholeTag = s.getNumWholeTag(); + b.numOfsDelta = s.getNumOfsDelta(); + b.numRefDelta = s.getNumRefDelta(); + b.numDeltaCommit = s.getNumDeltaCommit(); + b.numDeltaTree = s.getNumDeltaTree(); + b.numDeltaBlob = s.getNumDeltaBlob(); + b.numDeltaTag = s.getNumDeltaTag(); + b.timeNegotiating = s.getTimeNegotiating(); + b.timeReceiving = s.getTimeReceiving(); + b.timeCheckingConnectivity = s.getTimeCheckingConnectivity(); + b.timePreReceiveHooks = s.getTimePreReceiveHooks(); + b.timeProcessingCommands = s.getTimeProcessingCommands(); + return b; + } + /** * Set number of bytes read from the input stream * @@ -225,6 +319,63 @@ public Builder addWholeObject(int type) { return this; } + /** + * @param timeNegotiating + * time in milliseconds spent in the negotiation phase + * @return this + * @since 7.7 + */ + public Builder setTimeNegotiating(long timeNegotiating) { + this.timeNegotiating = timeNegotiating; + return this; + } + + /** + * @param timeReceiving + * time in milliseconds spent receiving the pack + * @return this + * @since 7.7 + */ + public Builder setTimeReceiving(long timeReceiving) { + this.timeReceiving = timeReceiving; + return this; + } + + /** + * @param timeCheckingConnectivity + * time in milliseconds spent checking the connectivity of + * the received pack + * @return this + * @since 7.7 + */ + public Builder setTimeCheckingConnectivity( + long timeCheckingConnectivity) { + this.timeCheckingConnectivity = timeCheckingConnectivity; + return this; + } + + /** + * @param timePreReceiveHooks + * time in milliseconds spent in pre-receive hooks + * @return this + * @since 7.7 + */ + public Builder setTimePreReceiveHooks(long timePreReceiveHooks) { + this.timePreReceiveHooks = timePreReceiveHooks; + return this; + } + + /** + * @param timeProcessingCommands + * time in milliseconds spent processing commands + * @return this + * @since 7.7 + */ + public Builder setTimeProcessingCommands(long timeProcessingCommands) { + this.timeProcessingCommands = timeProcessingCommands; + return this; + } + /** * Increment offset delta * @@ -299,6 +450,11 @@ ReceivedPackStatistics build() { s.numDeltaBlob = numDeltaBlob; s.numDeltaTag = numDeltaTag; s.numObjectsDuplicated = numObjectsDuplicated; + s.timeNegotiating = timeNegotiating; + s.timeReceiving = timeReceiving; + s.timeCheckingConnectivity = timeCheckingConnectivity; + s.timePreReceiveHooks = timePreReceiveHooks; + s.timeProcessingCommands = timeProcessingCommands; return s; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java index ac76e83d344..f6def25bfa5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java @@ -44,6 +44,7 @@ import org.eclipse.jgit.hooks.Hooks; import org.eclipse.jgit.hooks.PrePushHook; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectChecker; import org.eclipse.jgit.lib.ObjectId; @@ -1457,7 +1458,10 @@ public FetchResult fetch(final ProgressMonitor monitor, final FetchResult result = new FetchResult(); new FetchProcess(this, toFetch).execute(monitor, result, branch); - local.autoGC(monitor); + if (local.getConfig().getBoolean(ConfigConstants.CONFIG_FETCH_SECTION, + ConfigConstants.CONFIG_KEY_AUTOGC, true)) { + local.autoGC(monitor); + } return result; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 41ab8acf057..c3b2f618cec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -189,9 +189,12 @@ void checkWants(UploadPack up, List wants) throws PackProtocolException, IOException; } - /* + /** * {@link java.util.function.Consumer} doesn't allow throwing checked * exceptions. Define our own to propagate IOExceptions. + * + * @param + * input argument */ @FunctionalInterface private static interface IOConsumer { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java index 38c86a6ed04..5b520902410 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkRemoteObjectDatabase.java @@ -30,6 +30,7 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.PackedRefsTrait; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.util.IO; @@ -403,7 +404,7 @@ private void readPackedRefsImpl(final Map avail, if (line.charAt(0) == '#') { if (line.startsWith(RefDirectory.PACKED_REFS_HEADER)) { line = line.substring(RefDirectory.PACKED_REFS_HEADER.length()); - peeled = line.contains(RefDirectory.PACKED_REFS_PEELED); + peeled = line.contains(PackedRefsTrait.PEELED.value()); } continue; } 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 0b7c6204f2f..763bf26cd49 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -68,6 +68,8 @@ public abstract class SystemReader { private static volatile Boolean isLinux; + private static volatile Boolean isAndroid; + private static final String GIT_TRACE_PERFORMANCE = "GIT_TRACE_PERFORMANCE"; //$NON-NLS-1$ private static final boolean performanceTrace = initPerformanceTrace(); @@ -761,6 +763,25 @@ public boolean isLinux() { return isLinux.booleanValue(); } + /** + * Whether we are running on Android. + * + * @return true if we are running on Android. + * @since 7.7 + */ + public boolean isAndroid() { + if (isAndroid == null) { + String vendor = getProperty("java.vendor"); //$NON-NLS-1$ + if (vendor == null) { + isAndroid = Boolean.FALSE; + } else { + isAndroid = Boolean + .valueOf(vendor.toLowerCase().contains("android")); //$NON-NLS-1$ + } + } + return isAndroid.booleanValue(); + } + /** * Whether performance trace is enabled * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java index 0f45162e717..fdb2679cd26 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java @@ -15,10 +15,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; +import java.nio.file.Files; import java.util.ArrayList; import org.eclipse.jgit.internal.JGitText; @@ -556,9 +558,10 @@ public void writeTo(OutputStream os, ProgressMonitor pm) @Override public InputStream openInputStream() throws IOException { - if (onDiskFile == null) + if (onDiskFile == null) { return super.openInputStream(); - return new FileInputStream(onDiskFile); + } + return Files.newInputStream(onDiskFile.toPath()); } @Override @@ -566,7 +569,8 @@ public InputStream openInputStreamWithAutoDestroy() throws IOException { if (onDiskFile == null) { return super.openInputStreamWithAutoDestroy(); } - return new FileInputStream(onDiskFile) { + return new FilterInputStream( + Files.newInputStream(onDiskFile.toPath())) { @Override public void close() throws IOException { super.close(); diff --git a/pom.xml b/pom.xml index 50055da6338..975e7f99054 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.eclipse.jgit org.eclipse.jgit-parent pom - 7.6.0-SNAPSHOT + 7.8.0-SNAPSHOT JGit - Parent ${jgit-url} @@ -118,9 +118,9 @@ ${commit.time.iso} - 7.5.0.202512021534-r + 7.7.0.202606012155-r 1.10.15 - 2.17.1 + 2.19.0 0.1.55 1.1.3 1.2.3 @@ -130,14 +130,14 @@ 1.28.0 6.0.0 6.1.0 - 12.1.5 + 12.1.11 0.25.0 4.5.14 4.4.16 - 2.0.17 + 2.0.18 3.12.0 - 2.13.2 - 1.83 + 2.14.0 + 1.85 4.9.8.2 3.9.0 3.6.0 @@ -147,8 +147,8 @@ 2.16.1 3.0 3.27.7 - 5.18.1 - 1.18.4 + 5.19.1 + 1.18.11 jacoco @@ -899,7 +899,7 @@ commons-codec commons-codec - 1.20.0 + 1.22.1 @@ -911,25 +911,25 @@ org.apache.commons commons-io - 2.21.0 + 2.22.0 commons-logging commons-logging - 1.3.5 + 1.4.0 org.tukaani xz - 1.11 + 1.12 true - org.eclipse.jetty.ee10 - jetty-ee10-servlet + org.eclipse.jetty.ee11 + jetty-ee11-servlet ${jetty-version} @@ -969,6 +969,12 @@ ${slf4j-version} + + org.slf4j + jcl-over-slf4j + ${slf4j-version} + + com.google.code.gson gson @@ -1020,7 +1026,7 @@ org.mockito mockito-core - 5.21.0 + 5.23.0 diff --git a/tools/BUILD b/tools/BUILD index 379a9bd34cb..ff71fb502d3 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -35,398 +35,399 @@ default_java_toolchain( # https://github.com/bazelbuild/BUILD_file_generator/blob/master/tools/bazel_defs/java.bzl # However, feel free to add any additional errors. Thus far they have all been pretty useful. errorprone_checks = [ - "-XepDisableWarningsInGeneratedCode", - # The XepDisableWarningsInGeneratedCode disables only warnings, but - # not errors. We should manually exclude all files generated by - # AutoValue; such files always start $AutoValue_..... - # XepExcludedPaths is a regexp. If you need more paths - use | as - # separator. - "-XepExcludedPaths:.*/\\\\$$AutoValue_.*\\.java", - "-Xep:AlmostJavadoc:ERROR", - "-Xep:AlwaysThrows:ERROR", - "-Xep:AmbiguousMethodReference:ERROR", - # don't want to add dependency to errorprone - "-Xep:AnnotateFormatMethod:OFF", - "-Xep:ArgumentSelectionDefectChecker:ERROR", - "-Xep:ArrayAsKeyOfSetOrMap:ERROR", - "-Xep:ArrayEquals:ERROR", - "-Xep:ArrayFillIncompatibleType:ERROR", - "-Xep:ArrayHashCode:ERROR", - "-Xep:ArraysAsListPrimitiveArray:ERROR", - "-Xep:ArrayToString:ERROR", - "-Xep:AssertEqualsArgumentOrderChecker:WARN", - "-Xep:AssertionFailureIgnored:WARN", - "-Xep:AsyncCallableReturnsNull:ERROR", - "-Xep:AsyncFunctionReturnsNull:ERROR", - "-Xep:AutoValueConstructorOrderChecker:ERROR", - "-Xep:AutoValueFinalMethods:ERROR", - "-Xep:AutoValueImmutableFields:ERROR", - "-Xep:AutoValueSubclassLeaked:WARN", - "-Xep:BadAnnotationImplementation:ERROR", - "-Xep:BadComparable:ERROR", - "-Xep:BadImport:ERROR", - "-Xep:BadInstanceof:ERROR", - "-Xep:BadShiftAmount:ERROR", - "-Xep:BanSerializableRead:ERROR", - "-Xep:BigDecimalEquals:ERROR", - "-Xep:BigDecimalLiteralDouble:ERROR", - "-Xep:BoxedPrimitiveConstructor:ERROR", - "-Xep:BoxedPrimitiveEquality:ERROR", - "-Xep:BundleDeserializationCast:ERROR", - "-Xep:ByteBufferBackingArray:WARN", - "-Xep:CacheLoaderNull:ERROR", - "-Xep:CannotMockFinalClass:ERROR", - "-Xep:CanonicalDuration:ERROR", - "-Xep:CatchAndPrintStackTrace:ERROR", - "-Xep:CatchFail:ERROR", - "-Xep:ChainedAssertionLosesContext:ERROR", - "-Xep:ChainingConstructorIgnoresParameter:ERROR", - "-Xep:CharacterGetNumericValue:ERROR", - "-Xep:CheckNotNullMultipleTimes:ERROR", - "-Xep:CheckReturnValue:ERROR", - "-Xep:ClassCanBeStatic:ERROR", - "-Xep:ClassName:ERROR", - "-Xep:ClassNewInstance:ERROR", - "-Xep:CollectionIncompatibleType:ERROR", - "-Xep:CollectionToArraySafeParameter:ERROR", - "-Xep:CollectionUndefinedEquality:ERROR", - "-Xep:CollectorShouldNotUseState:ERROR", - "-Xep:ComparableAndComparator:ERROR", - "-Xep:ComparableType:ERROR", - "-Xep:CompareToZero:ERROR", - "-Xep:ComparingThisWithNull:ERROR", - "-Xep:ComparisonOutOfRange:ERROR", - "-Xep:CompatibleWithAnnotationMisuse:ERROR", - "-Xep:CompileTimeConstant:ERROR", - "-Xep:ComplexBooleanConstant:ERROR", - "-Xep:ComputeIfAbsentAmbiguousReference:ERROR", - "-Xep:ConditionalExpressionNumericPromotion:ERROR", - "-Xep:ConstantOverflow:ERROR", - "-Xep:DaggerProvidesNull:ERROR", - "-Xep:DangerousLiteralNull:ERROR", - "-Xep:DateChecker:ERROR", - "-Xep:DateFormatConstant:ERROR", - "-Xep:DeadException:ERROR", - "-Xep:DeadThread:ERROR", - "-Xep:DefaultCharset:ERROR", - "-Xep:DefaultPackage:ERROR", - "-Xep:DepAnn:ERROR", - "-Xep:DeprecatedVariable:ERROR", - "-Xep:DiscardedPostfixExpression:ERROR", - "-Xep:DoNotCall:ERROR", - "-Xep:DoNotCallSuggester:ERROR", - "-Xep:DoNotClaimAnnotations:ERROR", - "-Xep:DoNotMock:ERROR", - "-Xep:DoNotMockAutoValue:WARN", - "-Xep:DoubleBraceInitialization:ERROR", - "-Xep:DoubleCheckedLocking:ERROR", - "-Xep:DuplicateMapKeys:ERROR", - "-Xep:DurationFrom:ERROR", - "-Xep:DurationGetTemporalUnit:ERROR", - "-Xep:DurationTemporalUnit:ERROR", - "-Xep:DurationToLongTimeUnit:ERROR", - "-Xep:EmptyBlockTag:WARN", - "-Xep:EmptyCatch:ERROR", - "-Xep:EmptySetMultibindingContributions:ERROR", - "-Xep:EqualsGetClass:ERROR", - "-Xep:EqualsHashCode:ERROR", - "-Xep:EqualsIncompatibleType:ERROR", - "-Xep:EqualsNaN:ERROR", - "-Xep:EqualsNull:ERROR", - "-Xep:EqualsReference:ERROR", - "-Xep:EqualsUnsafeCast:ERROR", - "-Xep:EqualsUsingHashCode:ERROR", - "-Xep:EqualsWrongThing:ERROR", - "-Xep:ErroneousThreadPoolConstructorChecker:ERROR", - "-Xep:EscapedEntity:WARN", - "-Xep:ExpectedExceptionChecker:ERROR", - "-Xep:ExtendingJUnitAssert:ERROR", - "-Xep:ExtendsAutoValue:ERROR", - "-Xep:FallThrough:ERROR", - "-Xep:Finally:ERROR", - "-Xep:FloatCast:ERROR", - "-Xep:FloatingPointAssertionWithinEpsilon:ERROR", - "-Xep:FloatingPointLiteralPrecision:ERROR", - "-Xep:FloggerArgumentToString:ERROR", - "-Xep:FloggerFormatString:ERROR", - "-Xep:FloggerLogVarargs:ERROR", - "-Xep:FloggerSplitLogStatement:ERROR", - "-Xep:FloggerStringConcatenation:ERROR", - "-Xep:FormatString:ERROR", - "-Xep:FormatStringAnnotation:ERROR", - "-Xep:ForOverride:ERROR", - "-Xep:FragmentInjection:ERROR", - "-Xep:FragmentNotInstantiable:ERROR", - "-Xep:FromTemporalAccessor:ERROR", - "-Xep:FunctionalInterfaceClash:ERROR", - "-Xep:FunctionalInterfaceMethodChanged:ERROR", - "-Xep:FutureReturnValueIgnored:ERROR", - "-Xep:FuturesGetCheckedIllegalExceptionType:ERROR", - "-Xep:GetClassOnAnnotation:ERROR", - "-Xep:GetClassOnClass:ERROR", - "-Xep:GetClassOnEnum:ERROR", - "-Xep:GuardedBy:ERROR", - "-Xep:GuiceAssistedInjectScoping:ERROR", - "-Xep:GuiceAssistedParameters:ERROR", - "-Xep:HashtableContains:ERROR", - "-Xep:HidingField:WARN", - "-Xep:IdentityBinaryExpression:ERROR", - "-Xep:IdentityHashMapBoxing:ERROR", - "-Xep:IdentityHashMapUsage:ERROR", - "-Xep:IgnoredPureGetter:ERROR", - "-Xep:Immutable:ERROR", - "-Xep:ImmutableAnnotationChecker:ERROR", - "-Xep:ImmutableEnumChecker:ERROR", - "-Xep:ImmutableModification:ERROR", - "-Xep:Incomparable:ERROR", - "-Xep:IncompatibleArgumentType:ERROR", - "-Xep:IncompatibleModifiers:ERROR", - "-Xep:InconsistentCapitalization:WARN", - "-Xep:InconsistentHashCode:ERROR", - "-Xep:IncrementInForLoopAndHeader:ERROR", - "-Xep:IndexOfChar:ERROR", - "-Xep:InexactVarargsConditional:ERROR", - "-Xep:InfiniteRecursion:ERROR", - "-Xep:InheritDoc:ERROR", - "-Xep:InjectOnConstructorOfAbstractClass:ERROR", - "-Xep:InlineFormatString:ERROR", - "-Xep:InlineMeInliner:ERROR", - # don't want to add dependency to errorprone - "-Xep:InlineMeSuggester:OFF", - "-Xep:InlineMeValidator:ERROR", - "-Xep:InputStreamSlowMultibyteRead:ERROR", - "-Xep:InsecureCryptoUsage:ERROR", - "-Xep:InstanceOfAndCastMatchWrongType:ERROR", - "-Xep:InstantTemporalUnit:ERROR", - "-Xep:IntLongMath:ERROR", - "-Xep:InvalidBlockTag:ERROR", - "-Xep:InvalidInlineTag:ERROR", - "-Xep:InvalidJavaTimeConstant:ERROR", - "-Xep:InvalidLink:ERROR", - "-Xep:InvalidParam:ERROR", - "-Xep:InvalidPatternSyntax:ERROR", - "-Xep:InvalidThrows:ERROR", - "-Xep:InvalidThrowsLink:ERROR", - "-Xep:InvalidTimeZoneID:ERROR", - "-Xep:InvalidZoneId:ERROR", - "-Xep:IsInstanceIncompatibleType:ERROR", - "-Xep:IsInstanceOfClass:ERROR", - "-Xep:IsLoggableTagLength:ERROR", - "-Xep:IterableAndIterator:ERROR", - "-Xep:IterablePathParameter:ERROR", - "-Xep:JavaDurationGetSecondsGetNano:ERROR", - "-Xep:JavaDurationWithNanos:ERROR", - "-Xep:JavaDurationWithSeconds:ERROR", - "-Xep:JavaInstantGetSecondsGetNano:ERROR", - "-Xep:JavaLangClash:ERROR", - "-Xep:JavaLocalDateTimeGetNano:ERROR", - "-Xep:JavaLocalTimeGetNano:ERROR", - "-Xep:JavaPeriodGetDays:ERROR", - "-Xep:JavaTimeDefaultTimeZone:ERROR", - "-Xep:JavaUtilDate:WARN", - "-Xep:JdkObsolete:ERROR", - "-Xep:JodaConstructors:ERROR", - "-Xep:JodaDateTimeConstants:ERROR", - "-Xep:JodaDurationWithMillis:ERROR", - "-Xep:JodaInstantWithMillis:ERROR", - "-Xep:JodaNewPeriod:ERROR", - "-Xep:JodaPlusMinusLong:ERROR", - "-Xep:JodaTimeConverterManager:ERROR", - "-Xep:JodaToSelf:ERROR", - "-Xep:JodaWithDurationAddedLong:ERROR", - "-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR", - "-Xep:JUnit3TestNotRun:ERROR", - "-Xep:JUnit4ClassAnnotationNonStatic:ERROR", - "-Xep:JUnit4ClassUsedInJUnit3:ERROR", - "-Xep:JUnit4SetUpNotRun:ERROR", - "-Xep:JUnit4TearDownNotRun:ERROR", - "-Xep:JUnit4TestNotRun:ERROR", - "-Xep:JUnit4TestsNotRunWithinEnclosed:ERROR", - "-Xep:JUnitAmbiguousTestClass:ERROR", - "-Xep:JUnitAssertSameCheck:ERROR", - "-Xep:JUnitParameterMethodNotFound:ERROR", - "-Xep:LiteByteStringUtf8:ERROR", - "-Xep:LiteEnumValueOf:ERROR", - "-Xep:LiteProtoToString:ERROR", - "-Xep:LocalDateTemporalAmount:ERROR", - "-Xep:LockNotBeforeTry:ERROR", - "-Xep:LockOnBoxedPrimitive:ERROR", - "-Xep:LogicalAssignment:ERROR", - "-Xep:LongFloatConversion:ERROR", - "-Xep:LongLiteralLowerCaseSuffix:ERROR", - "-Xep:LoopConditionChecker:ERROR", - "-Xep:LoopOverCharArray:ERROR", - "-Xep:LossyPrimitiveCompare:ERROR", - "-Xep:MathAbsoluteRandom:ERROR", - "-Xep:MathRoundIntLong:ERROR", - "-Xep:MemoizeConstantVisitorStateLookups:ERROR", - "-Xep:MislabeledAndroidString:ERROR", - "-Xep:MissingCasesInEnumSwitch:ERROR", - "-Xep:MissingFail:ERROR", - "-Xep:MissingOverride:ERROR", - "-Xep:MissingSummary:WARN", - "-Xep:MissingSuperCall:ERROR", - "-Xep:MissingTestCall:ERROR", - "-Xep:MisusedDayOfYear:ERROR", - "-Xep:MisusedWeekYear:ERROR", - "-Xep:MixedDescriptors:ERROR", - "-Xep:MixedMutabilityReturnType:WARN", - "-Xep:MockitoUsage:ERROR", - "-Xep:ModifiedButNotUsed:ERROR", - "-Xep:ModifyCollectionInEnhancedForLoop:ERROR", - "-Xep:ModifyingCollectionWithItself:ERROR", - "-Xep:ModifySourceCollectionInStream:ERROR", - "-Xep:MultipleParallelOrSequentialCalls:ERROR", - "-Xep:MultipleUnaryOperatorsInMethodCall:ERROR", - "-Xep:MustBeClosedChecker:ERROR", - "-Xep:MutableConstantField:ERROR", - # Java provides no good alternative - "-Xep:MutablePublicArray:OFF", - "-Xep:NarrowingCompoundAssignment:ERROR", - "-Xep:NCopiesOfChar:ERROR", - "-Xep:NestedInstanceOfConditions:ERROR", - "-Xep:NonAtomicVolatileUpdate:ERROR", - "-Xep:NonCanonicalStaticImport:ERROR", - "-Xep:NonCanonicalType:ERROR", - "-Xep:NonFinalCompileTimeConstant:ERROR", - "-Xep:NonOverridingEquals:ERROR", - "-Xep:NonRuntimeAnnotation:ERROR", - "-Xep:NullableConstructor:ERROR", - "-Xep:NullablePrimitive:ERROR", - "-Xep:NullablePrimitiveArray:ERROR", - "-Xep:NullableVoid:ERROR", - "-Xep:NullOptional:ERROR", - "-Xep:NullTernary:ERROR", - "-Xep:ObjectEqualsForPrimitives:ERROR", - "-Xep:ObjectsHashCodePrimitive:ERROR", - "-Xep:ObjectToString:ERROR", - "-Xep:OperatorPrecedence:ERROR", - "-Xep:OptionalEquality:ERROR", - "-Xep:OptionalMapToOptional:ERROR", - "-Xep:OptionalMapUnusedValue:ERROR", - "-Xep:OptionalNotPresent:ERROR", - "-Xep:OptionalOfRedundantMethod:ERROR", - "-Xep:OrphanedFormatString:ERROR", - "-Xep:OutlineNone:ERROR", - "-Xep:OverlappingQualifierAndScopeAnnotation:ERROR", - "-Xep:Overrides:ERROR", - "-Xep:OverridesGuiceInjectableMethod:ERROR", - "-Xep:OverridesJavaxInjectableMethod:ERROR", - "-Xep:OverrideThrowableToString:ERROR", - "-Xep:PackageInfo:ERROR", - "-Xep:ParameterName:ERROR", - "-Xep:ParametersButNotParameterized:ERROR", - "-Xep:ParcelableCreator:ERROR", - "-Xep:PeriodFrom:ERROR", - "-Xep:PeriodGetTemporalUnit:ERROR", - "-Xep:PeriodTimeMath:ERROR", - "-Xep:PreconditionsCheckNotNullRepeated:ERROR", - "-Xep:PreconditionsInvalidPlaceholder:ERROR", - "-Xep:PreferredInterfaceType:OFF", - "-Xep:PrimitiveAtomicReference:ERROR", - "-Xep:PrivateSecurityContractProtoAccess:ERROR", - "-Xep:ProtectedMembersInFinalClass:ERROR", - "-Xep:ProtoBuilderReturnValueIgnored:ERROR", - "-Xep:ProtocolBufferOrdinal:ERROR", - "-Xep:ProtoDurationGetSecondsGetNano:ERROR", - "-Xep:ProtoFieldNullComparison:ERROR", - "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR", - "-Xep:ProtoRedundantSet:ERROR", - "-Xep:ProtoStringFieldReferenceEquality:ERROR", - "-Xep:ProtoTimestampGetSecondsGetNano:ERROR", - "-Xep:ProtoTruthMixedDescriptors:ERROR", - "-Xep:ProvidesMethodOutsideOfModule:ERROR", - "-Xep:RandomCast:ERROR", - "-Xep:RandomModInteger:ERROR", - "-Xep:ReachabilityFenceUsage:ERROR", - "-Xep:RectIntersectReturnValueIgnored:ERROR", - "-Xep:ReferenceEquality:ERROR", - "-Xep:RefersToDaggerCodegen:ERROR", - "-Xep:RemovedInJDK11:ERROR", - "-Xep:RequiredModifiers:ERROR", - "-Xep:RestrictedApiChecker:ERROR", - "-Xep:RethrowReflectiveOperationExceptionAsLinkageError:ERROR", - "-Xep:ReturnFromVoid:ERROR", - "-Xep:ReturnValueIgnored:ERROR", - "-Xep:RxReturnValueIgnored:ERROR", - "-Xep:SameNameButDifferent:ERROR", - "-Xep:SelfAssignment:ERROR", - "-Xep:SelfComparison:ERROR", - "-Xep:SelfEquals:ERROR", - "-Xep:ShortCircuitBoolean:ERROR", - "-Xep:ShouldHaveEvenArgs:ERROR", - "-Xep:SizeGreaterThanOrEqualsZero:ERROR", - "-Xep:StaticAssignmentInConstructor:ERROR", - "-Xep:StaticGuardedByInstance:ERROR", - "-Xep:StaticMockMember:ERROR", - "-Xep:StaticQualifiedUsingExpression:ERROR", - "-Xep:StreamToString:ERROR", - "-Xep:StringBuilderInitWithChar:ERROR", - "-Xep:StringEquality:ERROR", - "-Xep:StringSplitter:WARN", - "-Xep:SubstringOfZero:ERROR", - "-Xep:SuppressWarningsDeprecated:ERROR", - "-Xep:SwigMemoryLeak:ERROR", - "-Xep:SynchronizeOnNonFinalField:ERROR", - "-Xep:TemporalAccessorGetChronoField:ERROR", - "-Xep:TestParametersNotInitialized:ERROR", - "-Xep:TheoryButNoTheories:ERROR", - "-Xep:ThreadJoinLoop:ERROR", - "-Xep:ThreadLocalUsage:ERROR", - "-Xep:ThreadPriorityCheck:ERROR", - "-Xep:ThreeLetterTimeZoneID:WARN", - "-Xep:ThrowIfUncheckedKnownChecked:ERROR", - "-Xep:ThrowNull:ERROR", - "-Xep:TimeUnitConversionChecker:ERROR", - "-Xep:ToStringReturnsNull:ERROR", - "-Xep:TreeToString:ERROR", - "-Xep:TruthAssertExpected:ERROR", - "-Xep:TruthConstantAsserts:ERROR", - "-Xep:TruthGetOrDefault:ERROR", - "-Xep:TruthIncompatibleType:ERROR", - "-Xep:TruthSelfEquals:ERROR", - "-Xep:TryFailThrowable:ERROR", - "-Xep:TypeEquals:ERROR", - "-Xep:TypeNameShadowing:ERROR", - "-Xep:TypeParameterQualifier:ERROR", - "-Xep:TypeParameterShadowing:ERROR", - "-Xep:TypeParameterUnusedInFormals:ERROR", - "-Xep:UndefinedEquals:WARN", - "-Xep:UnescapedEntity:WARN", - "-Xep:UnnecessaryAssignment:ERROR", - "-Xep:UnnecessaryCheckNotNull:ERROR", - "-Xep:UnnecessaryLambda:ERROR", - "-Xep:UnnecessaryMethodInvocationMatcher:ERROR", - "-Xep:UnnecessaryMethodReference:ERROR", - "-Xep:UnnecessaryParentheses:ERROR", - "-Xep:UnnecessaryTypeArgument:ERROR", - "-Xep:UnrecognisedJavadocTag:ERROR", - "-Xep:UnsafeFinalization:ERROR", - "-Xep:UnsafeReflectiveConstructionCast:ERROR", - "-Xep:UnsynchronizedOverridesSynchronized:ERROR", - "-Xep:UnusedAnonymousClass:ERROR", - "-Xep:UnusedCollectionModifiedInPlace:ERROR", - "-Xep:UnusedException:ERROR", - "-Xep:UnusedMethod:WARN", - "-Xep:UnusedNestedClass:ERROR", - "-Xep:UnusedVariable:ERROR", - "-Xep:URLEqualsHashCode:ERROR", - "-Xep:UseBinds:ERROR", - "-Xep:UseCorrectAssertInTests:ERROR", - "-Xep:VariableNameSameAsType:ERROR", - "-Xep:VarTypeName:ERROR", - "-Xep:WaitNotInLoop:ERROR", - "-Xep:WakelockReleasedDangerously:ERROR", - "-Xep:WildcardImport:ERROR", - "-Xep:WithSignatureDiscouraged:ERROR", - "-Xep:WrongOneof:ERROR", - "-Xep:XorPower:ERROR", - "-Xep:ZoneIdOfZ:ERROR", + "-XepDisableWarningsInGeneratedCode", + # The XepDisableWarningsInGeneratedCode disables only warnings, but + # not errors. We should manually exclude all files generated by + # AutoValue; such files always start $AutoValue_..... + # XepExcludedPaths is a regexp. If you need more paths - use | as + # separator. + "-XepExcludedPaths:.*/\\\\$$AutoValue_.*\\.java", + "-Xep:AlmostJavadoc:ERROR", + "-Xep:AlwaysThrows:ERROR", + "-Xep:AmbiguousMethodReference:ERROR", + # don't want to add dependency to errorprone + "-Xep:AnnotateFormatMethod:OFF", + "-Xep:ArgumentSelectionDefectChecker:ERROR", + "-Xep:ArrayAsKeyOfSetOrMap:ERROR", + "-Xep:ArrayEquals:ERROR", + "-Xep:ArrayFillIncompatibleType:ERROR", + "-Xep:ArrayHashCode:ERROR", + "-Xep:ArraysAsListPrimitiveArray:ERROR", + "-Xep:ArrayToString:ERROR", + "-Xep:AssertEqualsArgumentOrderChecker:WARN", + "-Xep:AssertionFailureIgnored:WARN", + "-Xep:AsyncCallableReturnsNull:ERROR", + "-Xep:AsyncFunctionReturnsNull:ERROR", + "-Xep:AutoValueConstructorOrderChecker:ERROR", + "-Xep:AutoValueFinalMethods:ERROR", + "-Xep:AutoValueImmutableFields:ERROR", + "-Xep:AutoValueSubclassLeaked:WARN", + "-Xep:BadAnnotationImplementation:ERROR", + "-Xep:BadComparable:ERROR", + "-Xep:BadImport:ERROR", + "-Xep:BadInstanceof:ERROR", + "-Xep:BadShiftAmount:ERROR", + "-Xep:BanSerializableRead:ERROR", + "-Xep:BigDecimalEquals:ERROR", + "-Xep:BigDecimalLiteralDouble:ERROR", + "-Xep:BoxedPrimitiveConstructor:ERROR", + "-Xep:BoxedPrimitiveEquality:ERROR", + "-Xep:BundleDeserializationCast:ERROR", + "-Xep:ByteBufferBackingArray:WARN", + "-Xep:CacheLoaderNull:ERROR", + "-Xep:CannotMockFinalClass:ERROR", + "-Xep:CanonicalDuration:ERROR", + "-Xep:CatchAndPrintStackTrace:ERROR", + "-Xep:CatchFail:ERROR", + "-Xep:ChainedAssertionLosesContext:ERROR", + "-Xep:ChainingConstructorIgnoresParameter:ERROR", + "-Xep:CharacterGetNumericValue:ERROR", + "-Xep:CheckNotNullMultipleTimes:ERROR", + "-Xep:CheckReturnValue:ERROR", + "-Xep:ClassCanBeStatic:ERROR", + "-Xep:ClassName:ERROR", + "-Xep:ClassNewInstance:ERROR", + "-Xep:CollectionIncompatibleType:ERROR", + "-Xep:CollectionToArraySafeParameter:ERROR", + "-Xep:CollectionUndefinedEquality:ERROR", + "-Xep:CollectorShouldNotUseState:ERROR", + "-Xep:ComparableAndComparator:ERROR", + "-Xep:ComparableType:ERROR", + "-Xep:CompareToZero:ERROR", + "-Xep:ComparingThisWithNull:ERROR", + "-Xep:ComparisonOutOfRange:ERROR", + "-Xep:CompatibleWithAnnotationMisuse:ERROR", + "-Xep:CompileTimeConstant:ERROR", + "-Xep:ComplexBooleanConstant:ERROR", + "-Xep:ComputeIfAbsentAmbiguousReference:ERROR", + "-Xep:ConditionalExpressionNumericPromotion:ERROR", + "-Xep:ConstantOverflow:ERROR", + "-Xep:DaggerProvidesNull:ERROR", + "-Xep:DangerousLiteralNull:ERROR", + "-Xep:DateChecker:ERROR", + "-Xep:DateFormatConstant:ERROR", + "-Xep:DeadException:ERROR", + "-Xep:DeadThread:ERROR", + "-Xep:DefaultCharset:ERROR", + "-Xep:DefaultPackage:ERROR", + "-Xep:DepAnn:ERROR", + "-Xep:DeprecatedVariable:ERROR", + "-Xep:DiscardedPostfixExpression:ERROR", + "-Xep:DoNotCall:ERROR", + "-Xep:DoNotCallSuggester:ERROR", + "-Xep:DoNotClaimAnnotations:ERROR", + "-Xep:DoNotMock:ERROR", + "-Xep:DoNotMockAutoValue:WARN", + "-Xep:DoubleBraceInitialization:ERROR", + "-Xep:DoubleCheckedLocking:ERROR", + "-Xep:DuplicateMapKeys:ERROR", + "-Xep:DurationFrom:ERROR", + "-Xep:DurationGetTemporalUnit:ERROR", + "-Xep:DurationTemporalUnit:ERROR", + "-Xep:DurationToLongTimeUnit:ERROR", + "-Xep:EmptyBlockTag:WARN", + "-Xep:EmptyCatch:ERROR", + "-Xep:EmptySetMultibindingContributions:ERROR", + "-Xep:EqualsGetClass:ERROR", + "-Xep:EqualsHashCode:ERROR", + "-Xep:EqualsIncompatibleType:ERROR", + "-Xep:EqualsNaN:ERROR", + "-Xep:EqualsNull:ERROR", + "-Xep:EqualsReference:ERROR", + "-Xep:EqualsUnsafeCast:ERROR", + "-Xep:EqualsUsingHashCode:ERROR", + "-Xep:EqualsWrongThing:ERROR", + "-Xep:ErroneousThreadPoolConstructorChecker:ERROR", + "-Xep:EscapedEntity:WARN", + "-Xep:ExpectedExceptionChecker:ERROR", + "-Xep:ExtendingJUnitAssert:ERROR", + "-Xep:ExtendsAutoValue:ERROR", + "-Xep:FallThrough:ERROR", + "-Xep:Finally:ERROR", + "-Xep:FloatCast:ERROR", + "-Xep:FloatingPointAssertionWithinEpsilon:ERROR", + "-Xep:FloatingPointLiteralPrecision:ERROR", + "-Xep:FloggerArgumentToString:ERROR", + "-Xep:FloggerFormatString:ERROR", + "-Xep:FloggerLogVarargs:ERROR", + "-Xep:FloggerSplitLogStatement:ERROR", + "-Xep:FloggerStringConcatenation:ERROR", + "-Xep:FormatString:ERROR", + "-Xep:FormatStringAnnotation:ERROR", + "-Xep:ForOverride:ERROR", + "-Xep:FragmentInjection:ERROR", + "-Xep:FragmentNotInstantiable:ERROR", + "-Xep:FromTemporalAccessor:ERROR", + "-Xep:FunctionalInterfaceClash:ERROR", + "-Xep:FunctionalInterfaceMethodChanged:ERROR", + "-Xep:FutureReturnValueIgnored:ERROR", + "-Xep:FuturesGetCheckedIllegalExceptionType:ERROR", + "-Xep:GetClassOnAnnotation:ERROR", + "-Xep:GetClassOnClass:ERROR", + "-Xep:GetClassOnEnum:ERROR", + "-Xep:GuardedBy:ERROR", + "-Xep:GuiceAssistedInjectScoping:ERROR", + "-Xep:GuiceAssistedParameters:ERROR", + "-Xep:HashtableContains:ERROR", + "-Xep:HidingField:WARN", + "-Xep:IdentityBinaryExpression:ERROR", + "-Xep:IdentityHashMapBoxing:ERROR", + "-Xep:IdentityHashMapUsage:ERROR", + "-Xep:IgnoredPureGetter:ERROR", + "-Xep:Immutable:ERROR", + "-Xep:ImmutableAnnotationChecker:ERROR", + "-Xep:ImmutableEnumChecker:ERROR", + "-Xep:ImmutableModification:ERROR", + "-Xep:Incomparable:ERROR", + "-Xep:IncompatibleArgumentType:ERROR", + "-Xep:IncompatibleModifiers:ERROR", + "-Xep:InconsistentCapitalization:WARN", + "-Xep:InconsistentHashCode:ERROR", + "-Xep:IncrementInForLoopAndHeader:ERROR", + "-Xep:IndexOfChar:ERROR", + "-Xep:InexactVarargsConditional:ERROR", + "-Xep:InfiniteRecursion:ERROR", + "-Xep:InheritDoc:ERROR", + "-Xep:InjectOnConstructorOfAbstractClass:ERROR", + "-Xep:InlineFormatString:ERROR", + "-Xep:InlineMeInliner:ERROR", + # don't want to add dependency to errorprone + "-Xep:InlineMeSuggester:OFF", + "-Xep:InlineMeValidator:ERROR", + "-Xep:InputStreamSlowMultibyteRead:ERROR", + "-Xep:InsecureCryptoUsage:ERROR", + "-Xep:InstanceOfAndCastMatchWrongType:ERROR", + "-Xep:InstantTemporalUnit:ERROR", + "-Xep:IntLongMath:ERROR", + "-Xep:InvalidBlockTag:WARN", + "-Xep:InvalidInlineTag:ERROR", + "-Xep:InvalidJavaTimeConstant:ERROR", + "-Xep:InvalidLink:ERROR", + "-Xep:InvalidParam:ERROR", + "-Xep:InvalidPatternSyntax:ERROR", + "-Xep:InvalidThrows:ERROR", + "-Xep:InvalidThrowsLink:ERROR", + "-Xep:InvalidTimeZoneID:ERROR", + "-Xep:InvalidZoneId:ERROR", + "-Xep:IsInstanceIncompatibleType:ERROR", + "-Xep:IsInstanceOfClass:ERROR", + "-Xep:IsLoggableTagLength:ERROR", + "-Xep:IterableAndIterator:ERROR", + "-Xep:IterablePathParameter:ERROR", + "-Xep:JavaDurationGetSecondsGetNano:ERROR", + "-Xep:JavaDurationWithNanos:ERROR", + "-Xep:JavaDurationWithSeconds:ERROR", + "-Xep:JavaInstantGetSecondsGetNano:ERROR", + "-Xep:JavaLangClash:ERROR", + "-Xep:JavaLocalDateTimeGetNano:ERROR", + "-Xep:JavaLocalTimeGetNano:ERROR", + "-Xep:JavaPeriodGetDays:ERROR", + "-Xep:JavaTimeDefaultTimeZone:ERROR", + "-Xep:JavaUtilDate:WARN", + "-Xep:JdkObsolete:ERROR", + "-Xep:JodaConstructors:ERROR", + "-Xep:JodaDateTimeConstants:ERROR", + "-Xep:JodaDurationWithMillis:ERROR", + "-Xep:JodaInstantWithMillis:ERROR", + "-Xep:JodaNewPeriod:ERROR", + "-Xep:JodaPlusMinusLong:ERROR", + "-Xep:JodaTimeConverterManager:ERROR", + "-Xep:JodaToSelf:ERROR", + "-Xep:JodaWithDurationAddedLong:ERROR", + "-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR", + "-Xep:JUnit3TestNotRun:ERROR", + "-Xep:JUnit4ClassAnnotationNonStatic:ERROR", + "-Xep:JUnit4ClassUsedInJUnit3:ERROR", + "-Xep:JUnit4SetUpNotRun:ERROR", + "-Xep:JUnit4TearDownNotRun:ERROR", + "-Xep:JUnit4TestNotRun:ERROR", + "-Xep:JUnit4TestsNotRunWithinEnclosed:ERROR", + "-Xep:JUnitAmbiguousTestClass:ERROR", + "-Xep:JUnitAssertSameCheck:ERROR", + "-Xep:JUnitParameterMethodNotFound:ERROR", + "-Xep:LiteByteStringUtf8:ERROR", + "-Xep:LiteEnumValueOf:ERROR", + "-Xep:LiteProtoToString:ERROR", + "-Xep:LocalDateTemporalAmount:ERROR", + "-Xep:LockNotBeforeTry:ERROR", + "-Xep:LockOnBoxedPrimitive:ERROR", + "-Xep:LogicalAssignment:ERROR", + "-Xep:LongFloatConversion:ERROR", + "-Xep:LongLiteralLowerCaseSuffix:ERROR", + "-Xep:LoopConditionChecker:ERROR", + "-Xep:LoopOverCharArray:ERROR", + "-Xep:LossyPrimitiveCompare:ERROR", + "-Xep:MathAbsoluteRandom:ERROR", + "-Xep:MathRoundIntLong:ERROR", + "-Xep:MemoizeConstantVisitorStateLookups:ERROR", + "-Xep:MislabeledAndroidString:ERROR", + "-Xep:MissingCasesInEnumSwitch:ERROR", + "-Xep:MissingFail:ERROR", + "-Xep:MissingOverride:ERROR", + "-Xep:MissingSummary:WARN", + "-Xep:MissingSuperCall:ERROR", + "-Xep:MissingTestCall:ERROR", + "-Xep:MisusedDayOfYear:ERROR", + "-Xep:MisusedWeekYear:ERROR", + "-Xep:MixedDescriptors:ERROR", + "-Xep:MixedMutabilityReturnType:WARN", + "-Xep:MockitoUsage:ERROR", + "-Xep:ModifiedButNotUsed:ERROR", + "-Xep:ModifyCollectionInEnhancedForLoop:ERROR", + "-Xep:ModifyingCollectionWithItself:ERROR", + "-Xep:ModifySourceCollectionInStream:ERROR", + "-Xep:MultipleParallelOrSequentialCalls:ERROR", + "-Xep:MultipleUnaryOperatorsInMethodCall:ERROR", + "-Xep:MustBeClosedChecker:ERROR", + "-Xep:MutableConstantField:ERROR", + # Java provides no good alternative + "-Xep:MutablePublicArray:OFF", + "-Xep:NarrowingCompoundAssignment:ERROR", + "-Xep:NCopiesOfChar:ERROR", + "-Xep:NestedInstanceOfConditions:ERROR", + "-Xep:NonAtomicVolatileUpdate:ERROR", + "-Xep:NonCanonicalStaticImport:ERROR", + "-Xep:NonCanonicalType:ERROR", + "-Xep:NonFinalCompileTimeConstant:ERROR", + "-Xep:NonOverridingEquals:ERROR", + "-Xep:NonRuntimeAnnotation:ERROR", + "-Xep:NullableConstructor:ERROR", + "-Xep:NullablePrimitive:ERROR", + "-Xep:NullablePrimitiveArray:ERROR", + "-Xep:NullableVoid:ERROR", + "-Xep:NullOptional:ERROR", + "-Xep:NullTernary:ERROR", + "-Xep:ObjectEqualsForPrimitives:ERROR", + "-Xep:ObjectsHashCodePrimitive:ERROR", + "-Xep:ObjectToString:ERROR", + "-Xep:OperatorPrecedence:ERROR", + "-Xep:OptionalEquality:ERROR", + "-Xep:OptionalMapToOptional:ERROR", + "-Xep:OptionalMapUnusedValue:ERROR", + "-Xep:OptionalNotPresent:ERROR", + "-Xep:OptionalOfRedundantMethod:ERROR", + "-Xep:OrphanedFormatString:ERROR", + "-Xep:OutlineNone:ERROR", + "-Xep:OverlappingQualifierAndScopeAnnotation:ERROR", + "-Xep:Overrides:ERROR", + "-Xep:OverridesGuiceInjectableMethod:ERROR", + "-Xep:OverridesJavaxInjectableMethod:ERROR", + "-Xep:OverrideThrowableToString:ERROR", + "-Xep:PackageInfo:ERROR", + "-Xep:ParameterName:ERROR", + "-Xep:ParametersButNotParameterized:ERROR", + "-Xep:ParcelableCreator:ERROR", + "-Xep:PeriodFrom:ERROR", + "-Xep:PeriodGetTemporalUnit:ERROR", + "-Xep:PeriodTimeMath:ERROR", + "-Xep:PreconditionsCheckNotNullRepeated:ERROR", + "-Xep:PreconditionsInvalidPlaceholder:ERROR", + "-Xep:PreferredInterfaceType:OFF", + "-Xep:PrimitiveAtomicReference:ERROR", + "-Xep:PrivateSecurityContractProtoAccess:ERROR", + "-Xep:ProtectedMembersInFinalClass:ERROR", + "-Xep:ProtoBuilderReturnValueIgnored:ERROR", + "-Xep:ProtocolBufferOrdinal:ERROR", + "-Xep:ProtoDurationGetSecondsGetNano:ERROR", + "-Xep:ProtoFieldNullComparison:ERROR", + "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR", + "-Xep:ProtoRedundantSet:ERROR", + "-Xep:ProtoStringFieldReferenceEquality:ERROR", + "-Xep:ProtoTimestampGetSecondsGetNano:ERROR", + "-Xep:ProtoTruthMixedDescriptors:ERROR", + "-Xep:ProvidesMethodOutsideOfModule:ERROR", + "-Xep:RandomCast:ERROR", + "-Xep:RandomModInteger:ERROR", + "-Xep:ReachabilityFenceUsage:ERROR", + "-Xep:RectIntersectReturnValueIgnored:ERROR", + "-Xep:ReferenceEquality:ERROR", + "-Xep:RefersToDaggerCodegen:ERROR", + "-Xep:RemovedInJDK11:ERROR", + "-Xep:RequiredModifiers:ERROR", + "-Xep:RestrictedApiChecker:ERROR", + "-Xep:RethrowReflectiveOperationExceptionAsLinkageError:ERROR", + "-Xep:ReturnFromVoid:ERROR", + "-Xep:ReturnValueIgnored:ERROR", + "-Xep:RxReturnValueIgnored:ERROR", + "-Xep:SameNameButDifferent:ERROR", + "-Xep:SelfAssignment:ERROR", + "-Xep:SelfComparison:ERROR", + "-Xep:SelfEquals:ERROR", + "-Xep:ShortCircuitBoolean:ERROR", + "-Xep:ShouldHaveEvenArgs:ERROR", + "-Xep:SizeGreaterThanOrEqualsZero:ERROR", + "-Xep:StaticAssignmentInConstructor:ERROR", + "-Xep:StaticGuardedByInstance:ERROR", + "-Xep:StaticMockMember:ERROR", + "-Xep:StaticQualifiedUsingExpression:ERROR", + "-Xep:StreamToString:ERROR", + "-Xep:StringBuilderInitWithChar:ERROR", + "-Xep:StringEquality:ERROR", + "-Xep:StringSplitter:WARN", + "-Xep:SubstringOfZero:ERROR", + "-Xep:SuppressWarningsDeprecated:ERROR", + "-Xep:SwigMemoryLeak:ERROR", + "-Xep:SynchronizeOnNonFinalField:ERROR", + "-Xep:TemporalAccessorGetChronoField:ERROR", + "-Xep:TestParametersNotInitialized:ERROR", + "-Xep:TheoryButNoTheories:ERROR", + "-Xep:ThreadJoinLoop:ERROR", + "-Xep:ThreadLocalUsage:ERROR", + "-Xep:ThreadPriorityCheck:ERROR", + "-Xep:ThreeLetterTimeZoneID:WARN", + "-Xep:ThrowIfUncheckedKnownChecked:ERROR", + "-Xep:ThrowNull:ERROR", + "-Xep:TimeUnitConversionChecker:ERROR", + "-Xep:ToStringReturnsNull:ERROR", + "-Xep:TreeToString:ERROR", + "-Xep:TruthAssertExpected:ERROR", + "-Xep:TruthConstantAsserts:ERROR", + "-Xep:TruthGetOrDefault:ERROR", + "-Xep:TruthIncompatibleType:ERROR", + "-Xep:TruthSelfEquals:ERROR", + "-Xep:TryFailThrowable:ERROR", + "-Xep:TypeEquals:ERROR", + "-Xep:TypeNameShadowing:ERROR", + "-Xep:TypeParameterQualifier:ERROR", + "-Xep:TypeParameterShadowing:ERROR", + "-Xep:TypeParameterUnusedInFormals:ERROR", + "-Xep:UndefinedEquals:WARN", + "-Xep:UnescapedEntity:WARN", + "-Xep:UnnecessaryAssignment:ERROR", + "-Xep:UnnecessaryCheckNotNull:ERROR", + "-Xep:UnnecessaryLambda:ERROR", + "-Xep:UnnecessaryMethodInvocationMatcher:ERROR", + "-Xep:UnnecessaryMethodReference:ERROR", + "-Xep:UnnecessaryParentheses:ERROR", + "-Xep:UnnecessaryTypeArgument:ERROR", + "-Xep:UnrecognisedJavadocTag:ERROR", + "-Xep:UnsafeFinalization:ERROR", + "-Xep:UnsafeReflectiveConstructionCast:ERROR", + "-Xep:UnsynchronizedOverridesSynchronized:ERROR", + "-Xep:UnusedAnonymousClass:ERROR", + "-Xep:UnusedCollectionModifiedInPlace:ERROR", + "-Xep:UnusedException:ERROR", + "-Xep:UnusedMethod:WARN", + "-Xep:UnusedNestedClass:ERROR", + "-Xep:UnusedVariable:ERROR", + "-Xep:URLEqualsHashCode:ERROR", + "-Xep:UseBinds:ERROR", + "-Xep:UseCorrectAssertInTests:ERROR", + "-Xep:VariableNameSameAsType:ERROR", + "-Xep:VarTypeName:ERROR", + "-Xep:WaitNotInLoop:ERROR", + "-Xep:WakelockReleasedDangerously:ERROR", + "-Xep:WildcardImport:ERROR", + "-Xep:WithSignatureDiscouraged:ERROR", + "-Xep:WrongOneof:ERROR", + "-Xep:XorPower:ERROR", + "-Xep:ZoneIdOfZ:ERROR", ] - -exclude_in_tests = ["-Xep:EmptyBlockTag:WARN", - "-Xep:MissingSummary:WARN"] +exclude_in_tests = [ + "-Xep:EmptyBlockTag:WARN", + "-Xep:MissingSummary:WARN", +] java_package_configuration( name = "error_prone", @@ -436,7 +437,7 @@ java_package_configuration( java_package_configuration( name = "error_prone_tests", - javacopts = [ check for check in errorprone_checks if check not in exclude_in_tests], + javacopts = [check for check in errorprone_checks if check not in exclude_in_tests], packages = ["error_prone_packages_test"], ) diff --git a/tools/jgit-ee8/BUILD b/tools/jgit-ee8/BUILD new file mode 100644 index 00000000000..2c09b5aee48 --- /dev/null +++ b/tools/jgit-ee8/BUILD @@ -0,0 +1,55 @@ +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +sh_test( + name = "generated_srcs_test", + srcs = ["@com_googlesource_gerrit_bazlets//tools:generated_srcs_test.sh"], + args = [ + "--forbid", + "jakarta\\.servlet", + "--forbid", + "org\\.eclipse\\.jetty\\.ee11\\.servlet", + "--forbid", + "org\\.eclipse\\.jgit\\..*\\.ee8", + "--require-if-source", + "jakarta\\.servlet", + "javax\\.servlet", + "--module", + "org.eclipse.jgit.http.server/src/", + "$(location //org.eclipse.jgit.http.server.ee8:jgit-http-server-ee8-srcs)", + "$(locations //org.eclipse.jgit.http.server:srcs)", + "--module", + "org.eclipse.jgit.lfs.server/src/", + "$(location //org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8-srcs)", + "$(locations //org.eclipse.jgit.lfs.server:srcs)", + "--module", + "org.eclipse.jgit.junit.http/src/", + "$(location //org.eclipse.jgit.junit.http:junit-http-ee8-srcs)", + "$(locations //org.eclipse.jgit.junit.http:ee8-transform-srcs)", + "--module", + "org.eclipse.jgit.http.test/src/", + "$(location //org.eclipse.jgit.http.test.ee8:helpers-srcs)", + "$(locations //org.eclipse.jgit.http.test:helper-srcs)", + "--module", + "org.eclipse.jgit.http.test/tst/", + "$(location //org.eclipse.jgit.http.test.ee8:test-srcs)", + "$(locations //org.eclipse.jgit.http.test:test-srcs)", + "--module", + "org.eclipse.jgit.lfs.server.test/tst/", + "$(location //org.eclipse.jgit.lfs.server.test.ee8:test-srcs)", + "$(locations //org.eclipse.jgit.lfs.server.test:test-srcs)", + ], + data = [ + "//org.eclipse.jgit.http.server.ee8:jgit-http-server-ee8-srcs", + "//org.eclipse.jgit.http.server:srcs", + "//org.eclipse.jgit.http.test.ee8:helpers-srcs", + "//org.eclipse.jgit.http.test.ee8:test-srcs", + "//org.eclipse.jgit.http.test:helper-srcs", + "//org.eclipse.jgit.http.test:test-srcs", + "//org.eclipse.jgit.junit.http:ee8-transform-srcs", + "//org.eclipse.jgit.junit.http:junit-http-ee8-srcs", + "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8-srcs", + "//org.eclipse.jgit.lfs.server:srcs", + "//org.eclipse.jgit.lfs.server.test.ee8:test-srcs", + "//org.eclipse.jgit.lfs.server.test:test-srcs", + ], +) diff --git a/tools/jgit-ee8/README.md b/tools/jgit-ee8/README.md new file mode 100644 index 00000000000..d867a1ddb26 --- /dev/null +++ b/tools/jgit-ee8/README.md @@ -0,0 +1,69 @@ +# JGit EE8 Bazel bridge + +This package contains the Bazel-only bridge for source consumers that still run +on EE8 and `javax.servlet` while JGit master uses `jakarta.servlet`. + +JGit hosts this bridge because Gerrit is a known downstream that consumes JGit +from source through a git submodule and still runs Jetty 12 EE8. Keeping the +bridge in JGit lets Gerrit track JGit master and avoids maintaining a long-lived +servlet-4 branch just for Gerrit. That branch was never a stable JGit release +line, so it is not a sustainable way for Gerrit to receive JGit maintenance +updates. + +The bridge intentionally keeps the original JGit package names. It rewrites only +servlet API references from `jakarta.servlet` to `javax.servlet`, then compiles +generated jars from the rewritten source jars. + +Generated targets: + +* `//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8` +* `//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8` + +Do not put one of these generated jars and its canonical Jakarta counterpart on +the same classpath. They contain the same JGit classes. + +This is intentionally limited to source generation, build, and test. It does +not add Tycho, p2, or Maven Central publication machinery yet. + +Run: + +```sh +bazelisk test \ + //tools/jgit-ee8:generated_srcs_test \ + //org.eclipse.jgit.junit.http.ee8:tests +``` + +`//tools/jgit-ee8:generated_srcs_test` checks: + +* generated sources are derived from the canonical source filegroups +* generated srcjar entries use Java package paths +* generated sources preserve line counts for debugger breakpoints +* generated sources contain `javax.servlet`, not `jakarta.servlet` +* generated sources do not move JGit classes to an `.ee8` package + +The dedicated `org.eclipse.jgit.*.ee8` targets follow the Jetty 12 EE8 testing +model in a smaller form. Jetty generates EE8 main and test sources from the +canonical newer-EE modules and then runs the EE8 tests in the EE8 module graph. +JGit does the same for the servlet-facing tests: the HTTP/LFS test sources and +shared `junit-http` helpers are transformed to `javax.servlet`, wired to Jetty +EE8 test dependencies, and run against the generated EE8 JGit jars. + +`//org.eclipse.jgit.http.test.ee8:server_unit` is a fast, focused target for the +three HTTP server utility tests. It is not part of the default EE8 suite because +those classes already run under `//org.eclipse.jgit.http.test.ee8:http`. + +The test rewrite rules also map Jetty test helper imports from +`org.eclipse.jetty.ee11.servlet` to the Jetty EE8 packages needed by the tests. +They are intentionally test-only and separate from the production +`jakarta.servlet` to `javax.servlet` rules. + +Next steps: + +* Keep this source-consumer bridge while Gerrit runs on Jetty 12 EE8. +* Reuse these targets for other Bazel source consumers that need EE8 output. +* Move the generated-test JUnit helper to bazlets only if more generated-test + users need the same split between suite source labels and compiled sources. +* Add Maven/Tycho/p2 generation only when a non-Bazel consumer needs published + EE8 artifacts. +* Keep the canonical `srcs` filegroups aligned with each servlet-facing + `java_library` so new Java sources are transformed automatically. diff --git a/tools/maven-central/Pipfile b/tools/maven-central/Pipfile index cffba46d165..e34443d2a64 100644 --- a/tools/maven-central/Pipfile +++ b/tools/maven-central/Pipfile @@ -7,11 +7,11 @@ name = "pypi" requests = "*" argparse = "*" pyyaml = "*" +urllib3 = ">=2.7.0" [dev-packages] flake8 = "*" black = "*" [requires] -python_version = "3.12" -python_full_version = "3.12.9" +python_version = "3.14" diff --git a/tools/maven-central/Pipfile.lock b/tools/maven-central/Pipfile.lock index e5663989796..5839d925ef6 100644 --- a/tools/maven-central/Pipfile.lock +++ b/tools/maven-central/Pipfile.lock @@ -1,12 +1,11 @@ { "_meta": { "hash": { - "sha256": "096165cac35064650a41e592a40a9d1e13ae4022a1f6d43582534f1c3bf0dbf9" + "sha256": "28027cc52a42a1b801f3df250feac187373bed2c18fa6ddb4415dd6436ea4f2f" }, "pipfile-spec": 6, "requires": { - "python_full_version": "3.12.9", - "python_version": "3.12" + "python_version": "3.14" }, "sources": [ { @@ -251,11 +250,12 @@ }, "urllib3": { "hashes": [ - "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", - "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" + "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", + "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897" ], - "markers": "python_version >= '3.9'", - "version": "==2.6.3" + "index": "pypi", + "markers": "python_version >= '3.10'", + "version": "==2.7.0" } }, "develop": { diff --git a/tools/maven-central/README.md b/tools/maven-central/README.md index d4533d9cf78..821a61cb152 100644 --- a/tools/maven-central/README.md +++ b/tools/maven-central/README.md @@ -4,7 +4,7 @@ - you need to be a Eclipse JGit committer - install [jreleaser CLI](https://jreleaser.org/guide/latest/install.html) -- install [python 3.12](https://www.python.org/) +- install [python 3.14](https://www.python.org/) - install [pipenv](https://pipenv.pypa.io/en/latest/installation.html) we use below to setup a python virtualenv - we sign release tags and Maven artifacts using GPG. Follow [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) @@ -61,7 +61,7 @@ - prepare virtualenv for `download_release.py`: ``` $ cd tools/maven-central - $ pipenv --python 3.12 + $ pipenv --python 3.14 $ pipenv sync ``` - download a JGit release from repo.eclipse.org and create artifact signature files (`.asc`) @@ -87,7 +87,7 @@ - update the version in its `pom.xml` to the new JGit release you staged - delete all jgit artifacts from your local m2 repository ``` - $ rm -r ~/.m2/org/eclipse/jgit + $ rm -r ~/.m2/repository/org/eclipse/jgit ``` - build the jgit-built-test maven project to test if all artifacts of the new release can be downloaded and used in a build diff --git a/tools/maven-central/download_release.py b/tools/maven-central/download_release.py index 4ce44bc2318..fa24b2f74ce 100755 --- a/tools/maven-central/download_release.py +++ b/tools/maven-central/download_release.py @@ -10,7 +10,7 @@ from functools import partial -BASE_REPO_URL = "https://repo.eclipse.org/content/groups/releases" +BASE_REPO_URL = "https://repo.eclipse.org/content/repositories/releases" JGIT_GROUP_ID = "org.eclipse.jgit" JGIT_PARENT_ARTIFACT_ID = "org.eclipse.jgit-parent" DOWNLOAD_DIR = "staging-deploy" diff --git a/tools/version.sh b/tools/version.sh index 75f1a6a0d93..6cc6a900a1e 100755 --- a/tools/version.sh +++ b/tools/version.sh @@ -170,4 +170,4 @@ perl -pi~ -e ' ' $(git ls-files | grep pom.xml) find . -name '*~' | xargs rm -f -git diff +git --no-pager diff diff --git a/tools/workspace_status.py b/tools/workspace_status.py index 1186a4a77a6..f56120ca77a 100644 --- a/tools/workspace_status.py +++ b/tools/workspace_status.py @@ -23,7 +23,7 @@ import sys ROOT = os.path.abspath(__file__) -while not os.path.exists(os.path.join(ROOT, 'WORKSPACE')): +while not os.path.exists(os.path.join(ROOT, 'MODULE.bazel')): ROOT = os.path.dirname(ROOT) CMD = ['git', 'describe', '--always', '--match', 'v[0-9].*', '--dirty']